hsc2hs:使用 Haskell 改变 C 结构

2024-01-23

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

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

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
} deriving Show

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

我知道我需要将 TestData 类型分类为 Storable 并实现 peek、poke、sizeOf 和对齐,但我需要先看一个简单的示例,然后才能真正理解它。大多数教程都需要外部库,这使得它比需要的更加复杂。

以下是我看过的资源:

Stackoverflow - 如何使用 hsc2hs 绑定到常量、函数和数据结构? https://stackoverflow.com/questions/6056323/how-to-use-hsc2hs-to-bind-to-constants-functions-and-data-structures

Haskell Cafe - 适合初学者的 FFI https://groups.google.com/forum/#!topic/haskell-cafe/mJalEcZ-dTI

将 Haskell 接口写入 C 代码:hsc2hs https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/hsc2hs.html

Haskell 维基百科 - FFI https://en.wikibooks.org/wiki/Haskell/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);

这是一个完整的 C 程序示例,它将一个结构传递给 Haskell,然后 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 <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();
}

命令行- 编译文件并运行

$ hsc2hs HsFoo.hsc
$ ghc -c HsFoo.hs foo.c
$ ghc -no-hs-main foo.c HsFoo.o main.c -o main
$ ./main
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

hsc2hs:使用 Haskell 改变 C 结构 的相关文章

  • 在 DataView 的 RowFilter 中选择 DISTINCT

    我试图根据与另一个表的关系缩小 DataView 中的行范围 我使用的 RowFilter 如下 dv new DataView myDS myTable id IN SELECT DISTINCT parentID FROM myOthe
  • ClickOnce 应用程序错误:部署和应用程序没有匹配的安全区域

    我在 IE 中使用 FireFox 和 Chrome 的 ClickOnce 应用程序时遇到问题 它工作正常 异常的详细信息是 PLATFORM VERSION INFO Windows 6 1 7600 0 Win32NT Common
  • C中的malloc内存分配方案

    我在 C 中尝试使用 malloc 发现 malloc 在分配了一些内存后浪费了一些空间 下面是我用来测试 malloc 的一段代码 include
  • 在 C 中匹配二进制模式

    我目前正在开发一个 C 程序 需要解析一些定制的数据结构 幸运的是我知道它们是如何构造的 但是我不确定如何在 C 中实现我的解析器 每个结构的长度都是 32 位 并且每个结构都可以通过其二进制签名来识别 举个例子 有两个我感兴趣的特定结构
  • 当我们想要返回对象的引用时,为什么我们在赋值运算符中返回 *this 而通常(而不是 this)?

    我正在学习 C 和指针 我以为我理解了指针 直到我看到这个 一方面 asterix 运算符是解引用的 这意味着它返回值所指向的地址中的值 而与号 运算符则相反 它返回值存储的地址记忆 现在阅读有关赋值重载的内 容 它说 我们返回 this因
  • 为什么极端下派生类(多重虚拟继承)的大小包括超类成员大小的两倍?

    include
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • 在 Visual Studio 2010 中从 Fortran 调用 C++ 函数

    我想从 Fortran 调用 C 函数 为此 我在 Visual Studio 2010 中创建了一个 FORTRAN 项目 之后 我将一个 Cpp 项目添加到该 FORTRAN 项目中 当我要构建程序时出现以下错误 Error 1 unr
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • 在一个平台上,对于所有数据类型,所有数据指针的大小是否相同? [复制]

    这个问题在这里已经有答案了 Are char int long 甚至long long 大小相同 在给定平台上 不能保证它们的大小相同 尽管在我有使用经验的平台上它们通常是相同的 C 2011 在线草稿 http www open std
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • C# HashSet 只读解决方法

    这是示例代码 static class Store private static List
  • 如何禁用 fread() 中的缓冲?

    我正在使用 fread 和 fwrite 读取和写入套接字 我相信这些函数用于缓冲输入和输出 有什么方法可以在仍然使用这些功能的同时禁用缓冲吗 Edit 我正在构建一个远程桌面应用程序 远程客户端似乎 落后于服务器 我不知道可能是什么原因
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 使用 %d 打印 unsigned long long

    为什么我打印以下内容时得到 1 unsigned long long int largestIntegerInC 18446744073709551615LL printf largestIntegerInC d n largestInte
  • C++ 函数重载类似转换

    我收到一个错误 指出两个重载具有相似的转换 我尝试了太多的事情 但没有任何帮助 这是那段代码 CString GetInput int numberOfInput BOOL clearBuffer FALSE UINT timeout IN
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List

随机推荐

  • 与我的模型相关,我应该有多少个 DbContext 子类?

    我正在学习 ASP NET MVC 但我遇到了一些问题 到目前为止我读过的教程还没有以涵盖我的方式进行探讨 我尝试过搜索 但没有看到任何询问此问题的问题 不过 如果我错过了现有的 请原谅我 如果我有一个 ASP NET MVC 应用程序 它
  • 如何解决重叠实例

    我有以下代码 转换类似于转换 instance OVERLAPS Transformable a a where transform x x instance OVERLAPPABLE Transformable l l Transform
  • MySQL 上的奇怪完整性错误:#1452

    这有点奇怪 但我会尽力解释 我有 2 个模型 一个代表电子邮件消息 Message 另一个代表销售线索 AffiliateLead 当通过网站提交表单时 系统会生成潜在客户 然后发送电子邮件 消息模型有一个可选的 FK 返回到领导 从消息模
  • 使用 ExtJS 网格列标题中的 ListFilter 进行远程过滤

    我正在使用 ListFilter 插件来过滤网格面板上的结果 列定义是 header Provider filter type list store Ext getStore MyApp store Provider dataIndex p
  • 如何将数据从 iOS 发送回 Flutter?

    我正在尝试让 iOS 将数据发送回 flutter 更具体地说 是控制中心媒体控制 我正在开发一个音乐应用程序 我可以获取从 Flutter 发送到 iOS 的数据 从而允许它显示在媒体控件中 但是 如果我要控制播放暂停下一个上一个 我该如
  • Django:按月/年分组的日期属性的总和

    我想将此查询从 SQL 放入 Django select date format date Y m as month sum quantity as hours from hourentries group by date format d
  • VBA 代码无法连接到 SQL Server 2008

    我的代码无法连接到 Microsoft SQL Server 2008 中的数据库 它尝试连接 但随后出现以下错误 运行时错误 SQL Server 不存在或访问被拒绝 服务器受密码保护 但我认为是我造成的 任何帮助将不胜感激 发生错误的地
  • 如何仅翻转变换矩阵的一个轴?

    我有一个 4x4 变换矩阵 然而 在尝试转换后我注意到这个动作andY 轴的旋转方向相反 其余的都是正确的 我从其他一些 API 获得了这个矩阵 所以可能是坐标系的差异 那么 如何翻转变换矩阵的轴呢 如果只有平移 我可以在 Y 平移上添加减
  • 查找类以按名称实例化,无需命名空间或程序集? (。网)

    我想按名称 字符串 实例化一个类 而不指定命名空间或程序集 像这样 Unity语法 var processor container Resolve
  • HttpClient 与 HttpWebRequest

    我有一个大文件 我必须将其发送到 Web api 客户端 数据是多部分的 问题是 如果文件是通过 http Web 请求发送的 那么它会在 webapi 上快速上传 对于此请求 文件内容直接写入请求流 就好像通过 Httpclient ne
  • 绕过 Rsync 提示“您确定要继续连接吗”

    如何绕过这个问题或添加一个自动回答这个问题的标志 因为我正在尝试编写一个脚本 并且这个问题不断停止 rsync 的过程 因为在提示时无法在脚本中回答这个问题 Set the StrictHostKeyChecking选项no 在配置文件中或
  • OpenCV-Python 中的简单数字识别 OCR

    我正在尝试在 OpenCV Python cv2 中实现 数字识别 OCR 它仅用于学习目的 我想学习 OpenCV 中的 KNearest 和 SVM 功能 我有每个数字 100 个样本 即图像 我想和他们一起训练 有一个样本letter
  • 通过 Java 使用 Selenium Webdriver 缺少 size() 选项

    一直在参加一些课程来提高我使用 Selenium Webdriver 的自动化技能 我没有size 方法作为尝试计算页面内链接数量时的一个选项 我缺少一些罐子吗 导入库 java public static void main String
  • SVG 坐标系 - 点与像素

    阅读通过SVG 1 1 规范 http www w3 org TR SVG11 coords html 我试图理解用于定义初始视口的单位与文档其余部分使用的单位之间的关系 如果视口最初是使用点定义的
  • 我的 $Foo ATL 解决方案中的 ($Foo)PS 项目有何用途?

    在MSVC中创建一个ATL项目似乎创建的不是一个而是两个项目 后者的名称与前者相同 但名称后附加了 PS 第二个项目的目的是什么 我如何判断我是否需要它 COM 支持跨两个不同的线程 两个不同的进程或两台不同的机器进行接口方法调用 这就是所
  • 当前单元格展开时折叠其他 UITableViewCell

    我正在努力扩展我的UITableViewCell我可以扩展细胞 但我想崩溃UITableViewCell哪些没有被选中 我在代码中尝试的内容 var expandedCells Int IBOutlet weak var tableView
  • 基于视图和单元格的 NSTableView

    Cocoa 中基于单元格的表格视图和基于视图的表格视图之间的主要区别是什么 我的理解是基于单元格的表格视图基本上用于显示字符串 基于视图用于自定义单元格 诸如拖动行 选择等用户事件可以在基于视图中处理 基于单元格的表格视图使用 object
  • 如何完全禁用LogCat暂停?

    我对新的 LogCat 及其暂停功能有一个大问题 当我想从中读取一些较旧的条目时 我喜欢暂停输出的想法 但有时我希望输出不间断 这样我就可以触摸手机 并通过读取输出来查看它的反应 所以令我非常沮丧的是 LogCat 经常完全暂停 暂停按钮被
  • 在 div 上使用“display:table-cell”有缺点吗?

    我想要实现的是拥有一个固定宽度的第一个 div 和一个流动的第二个 div 它将填充父 div 宽度的其余宽度 div class clearfix div style width 100px some content div div so
  • hsc2hs:使用 Haskell 改变 C 结构

    我正在尝试编写一个与 C 通信的 Haskell 程序 最终通过 GHC iOS 用于 iOS 我希望它将一个字符串从 C 传递到 Haskell 让 Haskell 处理它 然后通过 hsc2s 将一些数据类型从 Haskell 返回到