【问题标题】:FFI: returning three Int#'s on the stackFFI:在堆栈上返回三个 Int#
【发布时间】: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# #)

我对以下内容的所有使用(编译,尽管使用 MagicHashGHCForeignImportPrimForeignFunctionInterfaceUnboxedTuplesMagicHash)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' 标志使所有内容都适合寄存器。管理堆栈更复杂”

标签: haskell ghc ffi


【解决方案1】:

如果您可以直接在汇编中而不是 C 中实现您的过程,那么很容易做到这一点。请参阅:http://brandon.si/code/almost-inline-asm-in-haskell-with-foreign-import-prim/。也许对于 GCD 算法,这对你来说没问题。

我整理了一个完整的阴谋集团项目here

【讨论】:

  • 哦,这实际上不是用于 GCD。这是为了使用 Rust 元组生成 Haskell 互操作。 :) 这仍然很有用!谢谢。
猜你喜欢
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 2020-10-27
  • 2013-09-27
  • 2015-02-09
  • 1970-01-01
  • 1970-01-01
  • 2012-11-23
相关资源
最近更新 更多