如何将字符串从Haskell传递给C?

时间:2013-07-23 13:50:22

标签: c haskell ffi

我想要做的就是将一个纯文本字符串从Haskell传递给C.但是,它说[Char]是一种不可接受的返回类型。我无法找到他们认为的原因,也无法找到可接受的返回类型。

我正在尝试制作一个非常简单的操作系统映像,我可以用Qemu启动它。

有谁知道怎么做?感谢。

    {-# LANGUAGE ForeignFunctionInterface #-}

    module Hello where

    import Foreign
    import Foreign.C.String
    import Foreign.C.Types

    hello :: String -> (CString -> IO a) -> IO a
    hello = "Hello, world!"

    foreign export ccall hello :: String -> (CString -> IO a) -> IO a

2 个答案:

答案 0 :(得分:14)

您需要CString

CString转到String

peekCString :: CString -> IO String

String转到CString

withCString :: String -> (CString -> IO a) -> IO a

还有module Foreign.C.String的Haddock文档。

可以在foreign声明中使用的一般类型列表被指定为Foreign Function Interface in the Haskell Report的一部分。

修改

好的,这是一个很小的例子,你可以做一些事情,有些基于你的示例代码。使用以下内容创建Haskell文件CTest.hs

module CTest where

import Foreign.C

hello :: IO CString
hello = newCString "hello"

foreign export ccall hello :: IO CString

然后使用以下内容创建一个C文件ctest.c

#include <stdio.h>
#include "CTest_stub.h"

int main (int argc, char *argv[]) {
  hs_init(&argc, &argv);
  printf("%s\n", hello());
  hs_exit();
  return 0;
}

然后编译并运行如下:

$ ghc CTest
[1 of 1] Compiling CTest            ( CTest.hs, CTest.o )
$ ghc -o ctest ctest.c CTest.o -no-hs-main
$ ./ctest
hello

答案 1 :(得分:-2)

我认为您需要的是System.IO.Unsafe.unsafePerformIO,然后再将IO CString转换为CString,然后再将CString发送到C。newCString会将Haskell字符串转换为IO CString。因此,System.IO.Unsafe.unsafePerformIO $ newCString a可以传递到C例程,该例程将接受类型为char*的输入。如果您的C例程返回静态char*,则System.IO.Unsafe.unsafePerformIO $ peekCString将给您Haskell字符串。您需要导入System.IO.UnsafeunsafePerformIOForeign.C.String(或Foreign.C.Types?)中有一个不推荐使用的实现,因此您必须使用完整路径。在找到unsafePerformIO之前,我经历了一段地狱-可能是因为人们对某种危险的东西过敏,以至于将不纯声明为纯净。如果newCString反复使用而没有清洁,可能会导致内存泄漏。 withCString可能是一个更好的选择-稍后会了解。