hsc2hs:用Haskell转换C结构 [英] hsc2hs: Mutate a C struct with Haskell

查看:175
本文介绍了hsc2hs:用Haskell转换C结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图编写一个与C通信的Haskell程序(最终通过GHC-iOS为iOS进行通信)。我希望它传递一个字符串从C到Haskell,让Haskell处理它,然后通过hsc2s从Haskell返回一些数据类型到C Structs。我找不到一个清晰,简单的教程。 Haskell在C语言中唯一需要的就是String,没有其他的了。



第一部分没有问题,向Haskell传递一个字符串。 b
$ b

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

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



C struct

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

Haskell数据类型

  data TestData = TestData {
a :: String,
b :: String,
c :: Int
}派生Show

- - 不知道类型会是什么样子
testParse :: CString - > TestData

我明白我需要将TestData类型化为Storable并实现peek,poke,sizeOf和alignment,但在我真正了解它之前,我需要看一个简单的例子。大多数教程需要外部库,并使其比需要的更复杂。



以下是我查看的资源:



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



Haskell Cafe - FFI为初学者

将Haskell接口写入C代码:hsc2hs



Haskell Wikibook - FFI



编辑:当前我卡住的地方(在C中调用setFoo时得到分段错误)
$ b $
 实例Storab le 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 ccallsetFoosetFoo :: Ptr Foo - > IO()

setFoo :: Ptr Foo - > IO()
setFoo f = do
newA< - newCStringabc
newB< - newCStringdef
poke f(Foo newA newB 123)

C代码片段

  foo * f; 
f = malloc(sizeof(foo));
foo-> a =bbb
foo-> b =aaa
foo-> c = 1
//这是不正确的
// setFoo(& f);
//这是正确的
setFoo(f);


解决方案

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



Foo.h

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

Foo.c

  #includefoo.h

HsFoo.hsc

  { - #LANGUAGE ForeignFunctionInterface# - } 
{ - #LANGUAGE CPP # - }

模块HsFoo其中

导入外部
导入Foreign.C

导入Control.Applicative
导入控制.Monad

#includefoo.h

data Foo = Foo {
a :: CString
,b :: CString
,c :: Int
}导出显示

实例可存储Foo其中
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)

国外出口ccallfree_HaskellPtr免费:: Ptr a - > IO()
国外出口ccallsetFoosetFoo :: Ptr Foo - > IO()
setFoo :: Ptr Foo - > IO()
setFoo f = do
newA< - newCStringabc
newB< - newCStringdef
poke f $ Foo newA newB 3
返回()

main.c $ b

  #include< stdio.h> 
#include< stdlib.h>
#includeHsFoo_stub.h
#includefoo.h

int main(int argc,char * argv []){
hs_init(& amp; ; argc,& argv);

foo * f;
f = malloc(sizeof(foo));
f-> a =你好;
f-> b =世界;
f-> c = 55555;

printf(foo已经在C:\\\\\\\\\\\\\:: %%\\\\\\\\\\\\\\\\: %%%%%%%%%%%%%%%%%%%%%%%%%%%, ; b,F-&℃);

setFoo(f);

printf(foo has has set in Haskell:\\\
a:%s\\\
b:%s\\\
c:%d\\\
,f-> a,f-> ; b,F-&℃);

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


I am trying to write a Haskell program that communicates with C (ultimately for iOS via GHC-iOS). I want it to pass a string from C to Haskell, have Haskell process it and then return some Data types from Haskell to C Structs via hsc2s. I have been unsuccessful at finding a clear, simple tutorial. The only thing Haskell needs from C is the String, nothing else.

I have no trouble with the very first part, passing a string to Haskell.

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

For test purposes and future reference, I just want to be able to handle something like the following.

C Struct

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

Haskell Data Type

data TestData =  TestData {
  a :: String,
  b :: String,
  c :: Int
} deriving Show

-- not sure what the type would look like
testParse :: CString -> TestData

I understand that I need to typeclass TestData as Storable and implement peek, poke, sizeOf and alignment, but I need to see a simple example before I can really understand it. Most of the tutorials require outside libraries and make it more complicated than it needs to be.

Here are the resources I've looked at:

Stackoverflow - How to use hsc2hs to bind to constants, functions and data structures?

Haskell Cafe - FFI for a beginner

Writing Haskell interfaces to C code: hsc2hs

Haskell Wikibook - FFI

Edit: Currently where I am stuck (gets segmentation error when setFoo is called in C)

Haskell Code Snippet

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 Code Snippet

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);

解决方案

This is a complete example of a C program that passes a struct to Haskell then Haskell mutates the values of that struct. It has no outside dependencies. You should be able to copy the code and run it if you have GHC. Hopefully this will serve as a simple, straightforward example for others.

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 <stdio.h>
#include <stdlib.h>
#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:\n  a: %s\n  b: %s\n  c: %d\n",f->a,f->b,f->c);

  setFoo(f);

  printf("foo has been set in Haskell:\n  a: %s\n  b: %s\n  c: %d\n",f->a,f->b,f->c);

  free_HaskellPtr(f->a);
  free_HaskellPtr(f->b);
  free(f);
  hs_exit();
}

Command Line - Compile files and run

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

这篇关于hsc2hs:用Haskell转换C结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆