【问题标题】:Can the FFI deal with arrays? If so, how?FFI 可以处理数组吗?如果是这样,怎么做?
【发布时间】:2012-04-08 22:23:16
【问题描述】:

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

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

【问题讨论】:

标签: arrays haskell ffi


【解决方案1】:

要将 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

【讨论】:

    【解决方案2】:

    如果您使用 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 函数修改了数据,那么您不应该这样做,而是应该 制作数据副本以不破坏引用透明度。

    如果你想使用标准的数组类型,你可以以同样的方式使用来自Data.Array.StorablewithStorableArray

    【讨论】:

    • 你打高尔夫球的版本没有使用sv 参数,我猜你只是不小心忽略了它(我试图编辑你的答案,但坚持我的编辑是 ≥ 6 个字符 :( )
    • @benmachine: 为你解决了这个问题:)
    【解决方案3】:

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

    【讨论】:

    • 是的,但 Haskell 指针运算以 字节 工作。因此,在 C 语言中,您可以编写 aPtr += 1 以移动到数组的下一个元素,而在 Haskell 中,您需要编写 next = aPtr + 1*sizeOf element。或者你可以使用Foreign.Marshal.Array.advancePtr
    • 当我导入ForeignForeign.Ptr 时,我没有看到PtrNum 实例,你从哪里得到的?
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2021-06-30
      • 2021-03-20
      • 2020-01-21
      • 2011-04-22
      • 2023-04-10
      • 1970-01-01
      • 2023-04-07
      • 2019-01-21
      • 2017-11-14
      相关资源
      最近更新 更多