我很确定可以通过FFI发送数组,但我找不到任何示例。例如,我有一个Haskell数组,我发送到int foo(int*)
函数,或者我有一个C数组int bar[64];
,我发送给Haskell。
理想情况下,我想要最有效的方法 - 我不希望任何堆分配或不必要的复制。另外,如果我可以在Haskell和C中使用Haskell的未装箱数组,那将是很好的。那么这样做的方法是什么?
答案 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函数修改了数据,那么您不应该这样做,而应该这样做 制作数据的副本,以免破坏参照透明度。
如果您想使用标准数组类型,则可以使用withStorableArray
中Data.Array.Storable
的相同方式使用{{1}}。
答案 1 :(得分:11)
答案 2 :(得分:4)
要将FFI Ptr转换为Haskell列表,您可以使用:
peekArray0 :: (Storable a, Eq a) => a -> Ptr a -> IO [a]
答案 3 :(得分:3)
与C一样,数组基本上是指向数组第一个成员的指针。您可以通过对指针进行算术来获得其他元素。 Ptr
是Num
的成员,因此您可以使用通常的算术运算。