简体   繁体   English

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

[英]How to pass a string from Haskell to C?

All I want to do is pass a plain-text string from Haskell to C. However, it says that [Char] is an unacceptable return type.我想要做的就是将一个纯文本字符串从 Haskell 传递给 C。但是,它说 [Char] 是一种不可接受的返回类型。 I can't find anywhere why they think it is, nor what acceptable return types are.我找不到他们认为的任何原因,也找不到可接受的返回类型。

I'm trying to make a very simple OS image that I can boot with Qemu.我正在尝试制作一个可以使用 Qemu 启动的非常简单的操作系统映像。

Does anyone know how to do this?有谁知道如何做到这一点? Thanks.谢谢。

    {-# 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

You want a CString .你想要一个CString

Going from CString to String :CStringString

peekCString :: CString -> IO String

Going from String to CString :StringCString

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

There's also Haddock documentation for module Foreign.C.String .还有模块Foreign.C.String Haddock 文档。

The general list of types that can be used in foreign declarations is specified as part of the Foreign Function Interface in the Haskell Report .可以在foreign声明中使用的类型的一般列表在 Haskell 报告中指定为外部函数接口的一部分。

Edit编辑

Ok, here's a very small example of a thing you can do, somewhat based on your sample code.好的,这是您可以做的事情的一个很小的例子,有点基于您的示例代码。 Create a Haskell file CTest.hs with the following contents:使用以下内容创建 Haskell 文件CTest.hs

module CTest where

import Foreign.C

hello :: IO CString
hello = newCString "hello"

foreign export ccall hello :: IO CString

Then create a C file ctest.c with the following contents:然后创建一个包含以下内容的 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;
}

Then compile and run as follows:然后编译运行如下:

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

I think what you need is System.IO.Unsafe.unsafePerformIO to convert IO CString to CString before sending the CString to C. newCString will convert a Haskell String to IO CString.我认为你需要的是System.IO.Unsafe.unsafePerformIO在将 CString 发送到 C 之前将 IO CString 转换为 CString。newCString 会将 Haskell 字符串转换为 IO CString。 Thus System.IO.Unsafe.unsafePerformIO $ newCString a can be passed to your C routine which will accept input of type char* .因此System.IO.Unsafe.unsafePerformIO $ newCString a可以传递给您的 C 例程,该例程将接受char*类型的输入。 If your C routine returns static char* then System.IO.Unsafe.unsafePerformIO $ peekCString will give you back a Haskell string.如果你的 C 例程返回 static char*那么System.IO.Unsafe.unsafePerformIO $ peekCString会给你一个 Haskell 字符串。 You need to import System.IO.Unsafe .您需要导入System.IO.Unsafe unsafePerformIO has an implementation in Foreign.C.String (or Foreign.C.Types ?) which is deprecated, so you have to use the full path. unsafePerformIOForeign.C.String (或Foreign.C.Types ?)中有一个已弃用的实现,因此您必须使用完整路径。 I had a hell of a time before I could find unsafePerformIO - probably because people are allergic to something that is so dangerous as to force declaration of impure to pure.在我找到unsafePerformIO之前,我unsafePerformIOunsafePerformIO ——可能是因为人们对某些危险的东西过敏,以至于强制声明不纯为纯。 newCString can lead to memory leaks if used repeatedly without cleaning. newCString如果不清理就重复使用会导致内存泄漏。 withCString may be a better option - will learn that later. withCString可能是更好的选择 - 稍后会学习。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM