DLang 与 C 语言交互
2023/6/25 1:23:25
本文主要是介绍DLang 与 C 语言交互,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
DLang 与 C 语言交互
很难受的是,这部分的文档太少了,根本没有 教程向 的文章。所以我写了此文以做分享。
本文原址链接(防止机器搬运):https://www.cnblogs.com/jeefy/p/17501476.html
阅读提示:请保证如下条件:
-
会基本C语言使用,以及其编译命令。
-
会基本D语言使用,以及其编译命令。
-
会使用
Makefile
之类的东西(不会也无所谓),不会dub
-
DLang 与 C 语言交互
- 最简单的例子
- 链接库
- 函数,参数?
最简单的例子
// 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!
接下来对于部分做出解释。
-
函数的声明:在
hello.d
中有一句extern (C) void hello();
,这就是函数的声明部分,由于 dlang 与 C++ 一样在处理函数名的时候会做一些变化,然而 C 中的函数名却是不变的,所以需要显式声明其函数名的处理方式:extern (C)
,也就是按照 C 的处理方式处理,这样才能调用到chello.o
中的hello
方法。 -
编译的命令:唯一需要注意的是需要把
.o
文件显示的放入编译命令中。 -
头文件:这是困扰我最久的一个点,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
中才存着数据。所以如此。
那么考虑不可变长数组。好像还是只能使用上面那种声明和调用方法……
这就是在传递参数的时候最需要注意的一个点。其他的参数类型转化可以参考:
-
https://dlang.org/spec/interfaceToC.html
-
https://wiki.dlang.org/D_binding_for_C
这篇关于DLang 与 C 语言交互的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-13Slicm 框架怎么进行用户认证?-icode9专业技术文章分享
- 2024-11-13在查询时将 map_coord 列的值转换为字符串有哪些方法?-icode9专业技术文章分享
- 2024-11-13如何将微信地区改成自定义文案?-icode9专业技术文章分享
- 2024-11-13DNS 缓存存在问题有哪些症状和解决方法?-icode9专业技术文章分享
- 2024-11-13HTTP 状态码(405)-Method Not Allowed是什么意思?-icode9专业技术文章分享
- 2024-11-13HTTP 状态码(500)-Internal Server Error是什么意思?-icode9专业技术文章分享
- 2024-11-13在 Element UI 中无法修改 $confirm 的取消按钮文字是什么原因?-icode9专业技术文章分享
- 2024-11-13unity XR是什么?-icode9专业技术文章分享
- 2024-11-13伴随矩阵是什么?-icode9专业技术文章分享
- 2024-11-13怎么使用grep -E 来查找匹配最后 2 条数据?-icode9专业技术文章分享