FFI可以处理数组吗?如果是这样,怎么样?

Pub*_*bby 21 arrays haskell ffi

我很确定可以通过FFI发送数组,但我找不到任何例子.例如,我有一个Haskell数组,我发送给一个int foo(int*)函数,或者我有一个C数组int bar[64];,我发送给Haskell.

理想情况下,我想要最有效的方式 - 我不希望任何堆分配或不必要的复制.另外,如果我可以在Haskell和C中使用Haskell的未装箱数组,那将是很好的.那么这样做的方法是什么?

dna*_*naq 17

如果您使用Data.Vector库,则可以根据需要使用Data.Vector.Storable.然后,您可以使用诸如unsafeToForeignPtr或unsafeWith之类的函数来访问基础外部指针.这允许您在不进行任何复制或编组的情况下调用C代码.

如果要从C阵列创建矢量,可以使用unsafeFromForeignPtr.

对于您可以使用的示例(假设c_foo不修改它的参数)

import Foreign.Ptr
import Foreign.C.Types
import System.IO.Unsafe (unsafePerformIO)
import qualified Data.Vector.Storable as SV

foreign import ccall unsafe "foo" c_foo :: Ptr CInt -> CInt

haskellFoo :: SV.Vector CInt -> CInt
haskellFoo sv = unsafePerformIO $
    SV.unsafeWith sv $ \ptr -> return (c_foo ptr)
Run Code Online (Sandbox Code Playgroud)

这可以打高尔夫球:

haskellFoo sv = unsafePerformIO $
    SV.unsafeWith sv (return . c_foo)
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的C函数修改了数据,那么您不应该这样做,而是应该复制数据以不破坏参照透明度.

如果你想使用标准阵列的类型,你可以使用withStorableArrayData.Array.Storable以同样的方式.


Dan*_*ner 11

FFI规范非常易读,因此您可能只想坐下来完成整个过程.但是,对于这个特定问题,您可以跳转到"编组"部分,特别是PtrStorable子部分,其中概述了可用于此的部分.