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

时间:2012-03-24 19:26:21

标签: arrays haskell ffi

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

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

4 个答案:

答案 0 :(得分: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)

这可以打高尔夫球:

haskellFoo sv = unsafePerformIO $
    SV.unsafeWith sv (return . c_foo)

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

如果您想使用标准数组类型,则可以使用withStorableArrayData.Array.Storable的相同方式使用{{1}}。

答案 1 :(得分:11)

FFI规范非常易读,因此您可能只想坐下来完成整个工作。但是,对于此特定问题,您可以跳转到“编组”部分,尤其是PtrStorable子部分,其中概述了可用于此的部分。

答案 2 :(得分:4)

要将FFI Ptr转换为Haskell列表,您可以使用:

peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a]

http://hackage.haskell.org/packages/archive/base/4.2.0.1/doc/html/Foreign-Marshal-Array.html#v%3ApeekArray0

答案 3 :(得分:3)

与C一样,数组基本上是指向数组第一个成员的指针。您可以通过对指针进行算术来获得其他元素。 PtrNum的成员,因此您可以使用通常的算术运算。