hsc2hs:使用Haskell改变C结构

我正在尝试编写一个与C通信的Haskell程序(最终通过GHC-iOS为iOS)。 我希望它将一个字符串从C传递给Haskell,让Haskell处理它,然后通过hsc2s将一些数据类型从Haskell返回到C Structs。 我找不到一个清晰,简单的教程是不成功的。 Haskell唯一需要的是String,没有别的。

我对第一部分没有任何问题,将字符串传递给Haskell。

testPrint :: CString -> IO () testPrint c = do s <- peekCString c putStrLn s 

出于测试目的和将来的参考,我只想能够处理如下的内容。

C结构

 struct testdata { char *a; char *b; int c; }; 

Haskell数据类型

 data TestData = TestData { a :: String, b :: String, c :: Int } deriving Show -- not sure what the type would look like testParse :: CString -> TestData 

我知道我需要将TestData类型化为Storable并实现peek,poke,sizeOf和alignment,但我需要先看一个简单的例子才能真正理解它。 大多数教程都需要外部库,并使其比需要的更复杂。

以下是我看过的资源:

Stackoverflow – 如何使用hsc2hs绑定到常量,函数和数据结构?

Haskell Cafe – 初学者的FFI

将Haskell接口写入C代码:hsc2hs

Haskell Wikibook – FFI

编辑:目前我被卡住的地方(在C中调用setFoo时出现分段错误)

Haskell代码片段

 instance Storable Foo where sizeOf = #{size foo} alignment = alignment (undefined :: CString) poke p foo = do #{poke foo, a} p $ a foo #{poke foo, b} p $ b foo #{poke foo, c} p $ c foo peek p = return Foo `ap` (#{peek foo, a} p) `ap` (#{peek foo, b} p) `ap` (#{peek foo, c} p) foreign export ccall "setFoo" setFoo :: Ptr Foo -> IO () setFoo :: Ptr Foo -> IO () setFoo f = do newA <- newCString "abc" newB <- newCString "def" poke f (Foo newA newB 123) 

C代码片段

 foo *f; f = malloc(sizeof(foo)); foo->a = "bbb" foo->b = "aaa" foo->c = 1 // this is incorrect // setFoo(&f); // this is correct setFoo(f); 

这是一个将结构传递给Haskell的C程序的完整示例,然后Haskell会改变该结构的值。 它没有外部依赖。 如果您有GHC,您应该能够复制代码并运行它。 希望这将成为其他人的一个简单,直接的例子。

foo.h中

 typedef struct { char *a; char *b; int c; } foo; 

foo.c的

 #include "foo.h" 

HsFoo.hsc

 {-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE CPP #-} module HsFoo where import Foreign import Foreign.C import Control.Applicative import Control.Monad #include "foo.h" data Foo = Foo { a :: CString , b :: CString , c :: Int } deriving Show instance Storable Foo where sizeOf _ = #{size foo} alignment _ = alignment (undefined :: CString) poke p foo = do #{poke foo, a} p $ a foo #{poke foo, b} p $ b foo #{poke foo, c} p $ c foo peek p = return Foo `ap` (#{peek foo, a} p) `ap` (#{peek foo, b} p) `ap` (#{peek foo, c} p) foreign export ccall "free_HaskellPtr" free :: Ptr a -> IO () foreign export ccall "setFoo" setFoo :: Ptr Foo -> IO () setFoo :: Ptr Foo -> IO () setFoo f = do newA <- newCString "abc" newB <- newCString "def" poke f $ Foo newA newB 3 return () 

main.c中

 #include  #include  #include "HsFoo_stub.h" #include "foo.h" int main(int argc, char *argv[]) { hs_init(&argc, &argv); foo *f; f = malloc(sizeof(foo)); f->a = "Hello"; f->b = "World"; f->c = 55555; printf("foo has been set in C:\na: %s\nb: %s\nc: %d\n",f->a,f->b,f->c); setFoo(f); printf("foo has been set in Haskell:\na: %s\nb: %s\nc: %d\n",f->a,f->b,f->c); free_HaskellPtr(f->a); free_HaskellPtr(f->b); free(f); hs_exit(); } 

命令行 - 编译文件并运行

 $ hsc2hs HsFoo.hsc $ ghc -c HsFoo.hs foo.c $ ghc -no-hs-main foo.c HsFoo.o main.c -o main $ ./main