DLang 与 C 语言交互

很难受的是,这部分的文档太少了,根本没有 教程向 的文章。所以我写了此文以做分享。

本文原址链接(防止机器搬运):https://www.cnblogs.com/jeefy/p/17501476.html

阅读提示:请保证如下条件:

  • 会基本C语言使用,以及其编译命令。

  • 会基本D语言使用,以及其编译命令。

  • 会使用 Makefile 之类的东西(不会也无所谓),不会 dub

最简单的例子

// chello.c
#include <stdio.h> void hello(void) {
puts("Hello World!");
}
// hello.d
extern (C) void hello(); void main() {
hello();
}

其实上面的两个程序的意义非常明显,就是最基本的 Hello World! 输出罢了。

我们有了上面两个文件后可以通过如下命令编译:

gcc -c chello.c
dmd hello.d chello.o

最终会得到一个 main 可执行文件(也可能是 main.exe,看系统)。运行它,你就得到了 Hello World!


接下来对于部分做出解释。

  1. 函数的声明:在 hello.d 中有一句 extern (C) void hello();,这就是函数的声明部分,由于 dlang 与 C++ 一样在处理函数名的时候会做一些变化,然而 C 中的函数名却是不变的,所以需要显式声明其函数名的处理方式:extern (C),也就是按照 C 的处理方式处理,这样才能调用到 chello.o 中的 hello 方法。

  2. 编译的命令:唯一需要注意的是需要把 .o 文件显示的放入编译命令中。

  3. 头文件:这是困扰我最久的一个点,dlang 如何使用 C 的头文件?后来才发现了一个误区,dlang 不存在头文件的说法,也就是说 dlang 无法 直接 使用 .h 文件。但是我们又需要声明函数怎么办?在官方文档中有这样一个命令:

    gcc -E -P program.h > program.lst

    这个命令的作用在于列出所有声明的东西(包括函数与结构体的声明)。在经过一定的修改后,就可以变为 .d 文件(做类似于头文件的作用)。


接下来我们尝试一点更加高级的东西。

链接库

我使用的例子是我自己在写的一个小东西。参见:

假如我需要使用一个简单的 SDL 程序以显示一个色块。我可以很轻易的写出如下代码:

// cshow.c
#include <stdio.h> #include <SDL2/SDL.h> // 省略了部分宏定义....避免冗长 int showColor(int R, int G, int B) {
SDL_PREWORK(50, 50);
while (!done) {
SDL_MYEQUIT(60); if (SDL_SetRenderDrawColor(ren, R, G, B, 255) < 0) {
fprintf(stderr, "Error Set render draw color: %s\n", SDL_GetError());
return -1;
}
SDL_RenderFillRect(ren, NULL);
SDL_RenderPresent(ren);
} SDL_CLEANUP;
return 0;
}

对于 dlang 中的调用也很明了:

// color.d

// show the color by SDL (written in C)
extern (C) int showColor(int, int, int);

只是问题出在编译的部分。

如果我们按照一下步骤编译:

gcc -c cshow.c `pkg-config sdl2 --cflags --libs`
dmd color.d cshow.o

我们最终会发现出现 undefined reference to ... 的错误。

在官方文档中并没有提及使用系统链接库的问题。但是 隐晦 的给出了解决方法。

我们直接找到 libSDL2.so 所在的位置。在我的系统中是 /usr/lib/x86_64-linux-gnu/libSDL2.so

于是编译命令新增一个部分,变为:

gcc -c cshow.c `pkg-config sdl2 --cflags --libs`
dmd color.d cshow.o /usr/lib/x86_64-linux-gnu/libSDL2.so

也就是直接把链接库也带上……属实给我整无语了。

啊,于是,我们不能真的吧所有库的位置全部找到,然后在编译的时候一个一个复制上去吧。所以就需要类似与 Make 或者 CMake, meson 之类的构建工具辅助我们。这部分不过多展开。


函数,参数?

有些时候,我们想要在 C 中使用 dlang 分配的内存。如:

// exmaple.c
void fillMem(int *dst, int size, int val) {
for (int i = 0; i < size; ++i)
dst[i] = val;
}

自然的,我们可以想到:

// example.d
// 错误示例!!!!!!!!!!!!!!!!!!!!
import std.stdio; extern (C) void fillMem(int[] dst, int size, int val); void main() {
int[] arr = new int[](3);
fillMem(arr, 3, 1);
writeln(arr[2]);
}

可以编译通过,然后运行……输出 0

讲道理应该是输出 1 才对。

那么很明显,类型出了问题,我们不应该如此操作。

于是参考官方文档。正确的姿势如下:

import std.stdio;
extern (C) void fillMem(int* dst, int size, int val); void main() {
int[] arr = new int[](3);
fillMem(arr.ptr, 3, 1);
writeln(arr[0]);
writeln(arr[1]);
writeln(arr[2]);
writeln(arr.length);
}

为什么如此?在 dlang 中,可变长数组其实有两个变量,可以理解为:

struct {
int length;
int * ptr;
}

当然,类型肯定不是这样的……

也就是说 arr.ptr 中才存着数据。所以如此。

那么考虑不可变长数组。好像还是只能使用上面那种声明和调用方法……

这就是在传递参数的时候最需要注意的一个点。其他的参数类型转化可以参考:

DLang 与 C 语言交互的更多相关文章

  1. FFI (语言交互接口(Foreign Function Interface))

    FFI(Foreign Function Interface)是用来与其它语言交互的接口, 在有些语言里面称为语言绑定(language bindings), Java 里面一般称为 JNI(Java ...

  2. nodejs与c语言交互应用实例

    nodejs与c/c++交互目前主流的方式有两种,node addon c++ 和 node-ffi . 1.node addon c++ 1)nodejs从c语言读取数据 addon.c #incl ...

  3. iOS - Swift 与 C 语言交互编程

    前言 作为一种可与 Objective-C 相互调用的语言,Swift 也具有一些与 C 语言的类型和特性,如果你的代码有需要,Swift 也提供了和常见的 C 代码结构混合编程的编程方式. 1.基本 ...

  4. swift语言混编--语言交互的接口

    FFI stands for Foreign Function Interface. A foreign function interface is the popular name for the ...

  5. python与c语言交互应用实例

    1.python向c语言写数据 1) 先将接收端编译成一个共享链接库gcc/arm-linux-gnueabihf-gcc -o bluetooth_proxy.so -shared -fPIC bl ...

  6. C/C++生成静态库动态库及语言交互

    C++静态库与动态库(比较透彻) Go中调用C的动态库与静态库 我的示例 文件结构 |- sample |- c |- libsample |- libsample.h |- libsample.cp ...

  7. 利用R语言进行交互数据可视化(转)

    上周在中国R语言大会北京会场上,给大家分享了如何利用R语言交互数据可视化.现场同学对这块内容颇有兴趣,故今天把一些常用的交互可视化的R包搬出来与大家分享. rCharts包 说起R语言的交互包,第一个 ...

  8. go语言入门

    Go语言最主要的特性: 自动垃圾回收 更丰富的内置类型 函数多返回值 错误处理 匿名函数和闭包 类型和接口 并发编程 反射 语言交互性 1.2.4 错误处理Go语言引入了3个关键字用 ...

  9. C++与Lua交互(三)

    通过上一篇的热身,我们对C++调用lua变量有了一个认识,现在让我们再深入一点,去探索一下如何调用lua的函数.表. Lua与宿主通讯的关键--栈 lua是个动态脚本语言,它的数据类型如何映射到C++ ...

  10. 脚本语言:Xmas(一)

    很偶然的一个想法,在从北京回成都的高铁上:我想要一个计算器.于是在火车上花了十来个小时,完成了一个模型:能够处理+-*/的优先级,以及"()",比如:1+(3+2)*4.这已是一年 ...

随机推荐

  1. Podman Desktop安装与使用-Windows10

    Podman Desktop安装与使用-Windows10 下载 containers/podman 地址 Podman Desktop Downloads 地址 我这里演示的是podman-v4.4 ...

  2. 3520. 【NOIP2013模拟11.7B组】原根(math)

    题目: 考试想法: 考试的时候觉得这些数学公式太恶心了,所以就直接跳过了. 正解: 直接暴力模拟就可以了. 代码: #include<bits/stdc++.h> using namesp ...

  3. [双目视差] 立体匹配算法推理 - SGBM算法(一)

    文章目录 立体匹配算法推理 - SGBM算法(一) 一.SGBM与SGM的区别 二.代价计算 立体匹配算法推理 - SGBM算法(一) SGBM立体匹配算法,总体来讲包含以下6个步骤: Preproc ...

  4. [OpenCV-Python] 17 形态学转换

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 17 形态学转换 17.1 腐蚀 17.2 膨胀 17.3 开运算 17.4 闭运算 17.5 形态学梯度 17.6 礼帽 17. ...

  5. 2023 Hubei Provincial Collegiate Programming Contest题解 C F H I J K M

    补题链接:https://codeforces.com/gym/104337 原文链接:https://www.eriktse.com/algorithm/1136.html M. Different ...

  6. 2022-04-27:用go语言重写ffmpeg的remuxing.c示例。

    2022-04-27:用go语言重写ffmpeg的remuxing.c示例. 答案2022-04-27: ffmpeg的remuxing.c是一个用于将多媒体文件从一种容器格式转换为另一种容器格式的命 ...

  7. 2022-07-27:小红拿到了一个长度为N的数组arr,她准备只进行一次修改, 可以将数组中任意一个数arr[i],修改为不大于P的正数(修改后的数必须和原数不同), 并使得所有数之和为X的倍数。

    2022-07-27:小红拿到了一个长度为N的数组arr,她准备只进行一次修改, 可以将数组中任意一个数arr[i],修改为不大于P的正数(修改后的数必须和原数不同), 并使得所有数之和为X的倍数. ...

  8. 2021-11-01:寻找重复数。给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数

    2021-11-01:寻找重复数.给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设 nums 只有 一个重复的整数 ...

  9. 2021-10-02:单词搜索。给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。单词必须按照字母

    2021-10-02:单词搜索.给定一个 m x n 二维字符网格 board 和一个字符串单词 word .如果 word 存在于网格中,返回 true :否则,返回 false .单词必须按照字母 ...

  10. cnpm : 无法加载文件 D:\nodejs\node_global\cnpm.ps1,因为在此系统上禁止运行 脚本。

    错误信息: cnpm : 无法加载文件 D:\nodejs\node_global\cnpm.ps1,因为在此系统上禁止运行 脚本.有关详细信息,请参阅 https:/go.microsoft.com ...