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

如何将字符串从Haskell传递到C?,c,haskell,ffi,C,Haskell,Ffi,我所要做的就是将一个纯文本字符串从Haskell传递到C。然而,它说[Char]是一个不可接受的返回类型。我找不到他们为什么会这么认为,也找不到什么是可接受的回报类型 我正在尝试制作一个非常简单的操作系统映像,可以用Qemu启动 有人知道怎么做吗?谢谢 {-# LANGUAGE ForeignFunctionInterface #-} module Hello where import Foreign import Foreign.C.String i

我所要做的就是将一个纯文本字符串从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

您需要一个
CString

CString
String

peekCString :: CString -> IO String
withCString :: String -> (CString -> IO a) -> IO a
String
转到
CString

peekCString :: CString -> IO String
withCString :: String -> (CString -> IO a) -> IO a
也有黑线鳕的文档

可以在
外部
声明中使用的类型的常规列表指定为的一部分

编辑 好的,这里有一个非常小的例子,说明了您可以做的一件事,多少是基于您的示例代码。创建包含以下内容的Haskell文件
CTest.hs

module CTest where

import Foreign.C

hello :: IO CString
hello = newCString "hello"

foreign export ccall hello :: IO CString
#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;
}
然后创建一个包含以下内容的C文件
ctest.C

module CTest where

import Foreign.C

hello :: IO CString
hello = newCString "hello"

foreign export ccall hello :: IO CString
#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;
}

我认为您需要的是
System.IO.Unsafe.unsafePerformIO
在将CString发送到C之前将IO CString转换为CString。newCString将把Haskell字符串转换为IO CString。因此,
System.IO.Unsafe.unsafePerformIO$newCString a
可以被传递到您的C例程,该例程将接受类型为
char*
的输入。如果您的C例程返回static
char*
,则
System.IO.Unsafe.unsafePerformIO$peek cstring
将返回一个Haskell字符串。您需要导入
System.IO.Unsafe
unsafePerformIO
Foreign.C.String
(或
Foreign.C.Types
?)中有一个不推荐使用的实现,因此您必须使用完整路径。我花了很长时间才发现
不安全的行为
——可能是因为人们对某种非常危险的东西过敏,以至于强迫宣布不纯净为纯净
newCString
如果在不清洁的情况下重复使用,可能会导致内存泄漏
withCString
可能是一个更好的选择-稍后将了解这一点。

我尝试过这个,但它仍然说[Char]是不可接受的,除此之外。我完全不熟悉Haskell和函数式编程,但不熟悉C或汇编。我把我当前的代码放在第一篇文章中。你的代码有几个问题
hello
是一个字符串文字,但您已经为它指定了一个函数类型。而
String
仍然出现在导出实体的类型中。您可能需要先阅读Haskell外部函数接口的一些介绍。我创建了一个hello函数,这样我可以导出它并从C调用它,让它返回一个字符串/字符数组。我读了FFI的介绍,但不太理解,因为他们没有解释如何导出Haskell函数。你需要在某个时候让asm调用hs_init()。没办法了!哦,但你也能做到!而且(后者是一个很好的概念证明,但是Research和Bitrotterd afaik——前者现在适合在现实世界中使用)这听起来不是一个好主意<代码>withCString帮助管理内存属性。如果使用
newCString
,则必须手动释放它。这并不一定不好,但如果调用
unsafePerformIO(newCString s)
则情况会变得更糟:您可能会发现很难确定何时可以安全地释放字符串。顺便说一句:作为一个使用
unsafePerformIO
和类似函数做过一些非琐碎工作的人,我想用最强烈的措辞说,它们只应该在真正必要的时候使用,而且几乎不应该被初学者使用(是的,有外国金融机构的例外,但这不是一个例外)。即使是真正的Haskell专家,比如GHC的首席开发人员,在使用
unsafePerformIO
时也会犯一些微妙但严重的错误。人们对它过敏是因为它具有高度过敏性!