很多语言都可以实现与C语言的互相调用,但我觉得D语言做的更好些,D与C的兼容是二进制兼容,不是在源码上的兼容,也就是说编译手的二进制文件是可以互相链接的。废话不多说,直接上例子
一、在D语言中调用C函数
首先是准备一个C函数
// foo.c#includeint test(){ printf("message from c\n"); return 123; // 随便返回一个值}
$ gcc -c foo.c
生成 foo.o
D代码
// bar.dimport std.stdio;extern(C) int test();void main(){ int rv = test(); writeln("test return is:", rv);}
$ dmd bar.d foo.o
./bar
message from c
test return is:123
可以看到,要调用C的函数只需要使用 extern(C) 声明函数,然后一起编译即可,如果是调用C生成的so,只需要在编译D程序的时候加上链接函数即可如 dmd bar.d -L-lxx
是不是很简单呢,跟C++调用C看上去一样,只是编译的时候D需要的是二进制文件,C++需要的是源代码
网上有很多资料都说D对C的支持是不完全的,这么说虽然也没问题,但是明显好像是说支持的不好,其实支持的非常好,只是不同的编译器对C都会有些各自的扩展,这方面支持的不算好
从D调用C没什么,但是能从C调用D函数要怎么做呢,这方面能作到和C++一样方便的就只有D了,在D语言中分两种情况,一种是简单的函数,另一种是D函数中用到了D中的高级特性,如类,关联数组,委托等,简单函数只要声明为extern(C) 就可以了,如果使用了高级特性也不难,只不过没有这方面的资料来说明,需要调用D运行库中的额外两个函数,rt_init() 和 rt_term ,相信看到名子就能理解他的意思了,要想支持D中的高级特性只需要初始化D运行时库,在结束的时候释放D运行库的资源即可,看下面的例子
D代码
import std.stdio;class Test // 使用类{ int a = 100; void printA() { writeln(this.a); // 使用D标准IO函数 } auto getAA() { return ["k1":111, "k2": 222, "k3": 334]; // 返回一个关联数组 } }extern(C) void test() // 需要声明为extern(C){ auto t = new Test; t.printA(); writeln(t.getAA());}
C代码
// bar.cint rt_init();int rt_term();int test();int main(){ rt_init(); test(); // ... rt_term();}
编译
$ dmd -c foo.d
$ gcc -o main bar.c foo.o -lphobos2 -L /usr/share/dmd/lib/
./main
100
["k1":111, "k2":222, "k3":334]
我们看到,上面说到的额外两个函数的用法
需要注意的是编译的时候需要链接 libphobos2这个库,这个是D的标准库,我的是在Mac下的默认安装目录,根据情况找到安装目录即可
与C语言互调除了C++外,只有D做的最简单了,只比C++多了两个额外的函数调用,除了extern(C) 声明外,其它代码就正常写就行了,不需额外的对C的兼容做努力,在C代码中需要多调用两个函数,如果想要C不知道这两个函数的存在,可以把这两个函数的调用放在D代码里调用就行了,即初始化和释放动作自己负责,不给调用者带来麻烦
如果您对这方面的内容还有什么疑惑,欢迎交流