2

可能重复:
FFI 可以处理数组吗?如果是这样,怎么做?

我有一个用 Haskell 编写的小型汇编程序,它接受一个带有汇编代码的字符串并返回一串二进制机器代码。我希望能够通过将此 Haskell 库构建为共享库来在 C 中使用此函数。二进制机器代码可以包含空值,因此我不能CString用作返回类型,因为这是一个常规的以空值结尾的字符串。而且由于我不能CStringLen在 FFI 中使用 a 作为返回值。

我应该使用什么类型来实现这一点?

内部汇编函数的类型签名:

assembly :: String -> ByteString 

这是此函数的输入和输出示例:

输入:

decl r0 0x02
decl r1 0x10
add r0 r1 
mov rr rs

输出(二进制数据表示为十六进制,每行 3 个字节):

01 00 02
01 01 10
03 00 01
02 05 04
4

3 回答 3

3

如果我用 C 语言编写它,我可能会给它一个这样的原型:

void assemble(char **out, size_t *outlen, const char *in);

这转化为这样的东西(未经测试):

import qualified Assemble -- your module with the "assemble" function

import Foreign.Ptr (Ptr)
import Foreign.Storable (poke)
import Foreign.Marshal.Utils (copyBytes)
import Foreign.Marshal.Alloc (mallocBytes)
import Foreign.C.Types (CSize, CChar)
import Foreign.C.String (CString, peekCString)
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)

foreign export ccall assemble :: Ptr (Ptr CChar) -> Ptr CSize -> CString -> IO ()

assemble :: Ptr (Ptr CChar) -> Ptr CSize -> String -> IO ()
assemble out outlen instrptr = do
  instr <- peekCString instrptr
  unsafeUseAsCStringLen (Assemble.assemble instr) $ \(p, n) -> do
    outval <- mallocBytes n
    copyBytes outval p n
    poke out outval
    poke outlen (fromIntegral n)

这会将数据复制到一个malloc区域,这很好,因为它是“安全的”,并且 C 代码不需要做任何特殊的事情来释放它(除了free())。

于 2012-09-30T14:26:48.043 回答
1

你能用原始指针和手动内存分配做点什么吗?(请参阅Foreign.Marshal.Alloc。)听起来你可以只malloc用一块内存并在那里写你的二进制数据......

于 2012-09-30T14:24:04.580 回答
0

我对 Haskell 的了解不够确定,但是您不能将额外的 out 参数长度传递给 haskell 函数吗?从函数返回时,长度会告诉 c 程序返回的字符串的大小。我相信我在 c 和 python 之间做过类似的事情。

或者,您不能返回一个自定义对象,例如具有长度字段的 c++ 字符串。即使您使用纯 c,如果它们是在 c 和 haskell 之间共享类型的一种方式(我相信应该存在),您也可以编写一个带有 char 数组和长度字段的小字符串结构,并从 haskell 返回该对象。

于 2012-09-30T09:57:27.640 回答