【发布时间】:2017-12-04 19:52:14
【问题描述】:
有没有办法从外部函数调用返回堆栈上的三个Int#?这是 C 代码(或生成与我真正感兴趣的对象文件等效的目标文件的 C 代码):
struct Tuple {
int bezout1, bezout2, gcd;
}
struct Tuple extendedGcd(int a, int b) {
/* elided */
}
由于ccall 不支持(# Int#, Int#, Int# #),因此无法编译:
foreign import ccall "extendedGcd"
extendedGcd :: Int# -> Int# -> (# Int#, Int#, Int# #)
我对以下内容的所有使用(编译,尽管使用 MagicHash、GHCForeignImportPrim、ForeignFunctionInterface、UnboxedTuples 和 MagicHash)seg-fault:
foreign import prim "extendedGcd"
extendedGcd :: Int# -> Int# -> (# Int#, Int#, Int# #)
我可以找到一些证据表明有人努力解决此类问题:
我想这是一个常见问题,但我找不到任何可行的示例。这是可能吗?如果没有人再关心这个了(在某个地方有 Trac 票吗?)
【问题讨论】:
-
您要导入的 C 函数的类型是什么?我认为它在 C 中的类型完全决定了您可以在 Haskell 中分配给它的类型。
ccall旨在模拟 C 调用约定;由于 C 本身没有多重返回的概念,因此ccall中也不存在。我认为自动结构编组的提议被取消了,转而使用c2hs或类似的方法来自动生成编组结构的代码。 -
@user2407038 当然它有一个 C 类型(我已经包含了一些代码),但是
Storable实例c2hs生成所有假设我正在传递一个指针。在这里,我想传递一个未装箱的产品(堆栈上只有三个原始整数)。我的理解是,在 Haskell 中做到这一点的唯一方法是通过未装箱的元组。 -
确实,没有在某处分配临时内存的情况下从 C 函数返回结构的简单方法。如果这对性能造成太大的损失(或这样做的其他障碍),唯一的选择是使用
prim并像您所做的那样返回一个未装箱的元组。但是如果你的函数是一个普通的 C 函数,它将不符合prim函数必须使用的 GHC 调用约定。你必须为你的函数写一个 C-- 包装器。 -
@user2407038 我很想看到这样的例子!
-
@user2407038 是的 - 我已经读过第二次了。有一个烦人的警告:“许多消息不适合此处可用的 5 个空闲寄存器 (R2-R6),需要部分加载到堆栈中。在此示例中,我只是丢弃了 'printable' 标志使所有内容都适合寄存器。管理堆栈更复杂”