【问题标题】:Passing struct-like data between C and Haskell via the FFI通过 FFI 在 C 和 Haskell 之间传递类似结构的数据
【发布时间】:2016-09-03 17:49:02
【问题描述】:

考虑一个看起来像这样的 Haskell 数据类型

data MyData = MyData { arrInt :: [Int] , arrDouble :: [Double], arraySize :: N }

这里 N 代表 MyData 记录的两个数组的大小。

是否可以将 this(或 MyData 对象的某种 Haskell“指针”)传递给看起来像这样的 C 函数。

int myfunc (int* a, double* b, int N)

我可以使用 FFI 调用 C 函数,接受和返回简单的数据类型,如 Double、Int、Char 等。但对于更复杂的类型,我不知道该怎么做。

【问题讨论】:

  • C 例程会修改这两个数组吗?
  • @chi 不。至少不适合我想到的应用程序。

标签: c haskell ffi


【解决方案1】:

你可以这样做:

import Foreign
import Foreign.C

myfunc :: MyData -> IO CInt
myfunc d =
    withArray (map fromIntegral $ arrInt d) $ \arr1 ->
        withArray (map CDouble $ arrDouble d) $ \arr2 ->
            c_myfunc arr1 arr2 (fromIntegral $ arraySize d)

foreign import ccall safe "myfunc"
    c_myfunc :: Ptr CInt -> Ptr CDouble -> CInt -> IO CInt

【讨论】:

  • 有趣! “d”中的数据是否被复制到一个单独的相应 C-struct 中,c_myfunc 在该 C-struct 上运行?还是 c_myfunc 直接对“d”记录进行操作,就好像它是 C 类型一样。这对于处理大数据时的性能非常重要。
  • 它被复制到一个单独的结构中。一般来说,haskell 对大多数复杂数据类型的表示与 C 显着不同,因此在 C 之间传递数据涉及大量复制。在少数不需要使用两种语言之一对数据进行任何处理的情况下,您可以避免这种情况。在这种情况下,您只需以执行处理的语言格式存储数据。
  • @smilingbuddha 需要一份副本。 [Int] 的 Haskell 内存布局不是像 C 中那样的连续数组。请注意,如果函数修改了这些数组,则更改将不会反映在纯 MyData 参数中,当然。如果需要,可以让myfunc 返回一个新更新的MyData
  • @chi 谢谢!如果不是 [Int] 我有类似 REPA 数组的东西,我认为它们本质上是存储在连续内存中的数组?
  • 看看Data.Vector.StorableData.Vector.Storable.Mutable
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-08
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 2013-11-15
  • 2013-06-03
  • 1970-01-01
相关资源
最近更新 更多