C 语言接口 2.014

D 的设计就是要在目标系统上能够很好地符合于 C 编译器。D 通过依赖于目标环境上的 C
运行库,来弥补没有自己的 VM(虚拟机) 的不足。将大量现有的 C 的 API 移植到 D 或者
用 D 来进行封装,并没有多大意义。直接调用它们不是要方便得多。
如果采用跟 C 编译器相同的数据类型、内存分布(layout)和函数调用/返回序列,那么它就可
以实现。
5.1 调用 C 函数
D 可以直接调用 C 函数。不需要封装函数、参数变换,同时也不需要将 C 函数放到单独的
DLL 中。
C 函数必须被声明,而且必须指定调用协定,大部份情况下为 "C" 调用约定,例如:
extern (C) int strcmp(char* string1, char* string2);
然后就可以在 D 代码中很自然的调用它们了:
import std.string;
int myDfunction(char[] s)
{
return strcmp(std.string.toStringz(s), "foo");
}
需要注意以下几点:
• D 知道 C 函数名的变换规则及函数的调用/返回指令序列。
• C 函数不能被另一个同名的 C 函数重载。
• D 中没有如 __cdecl、__far、__stdcall、__declspec 或者如此之类的 C 类型修饰符。
这个可以使用一些特性,如 extern (C),来进行处理。
• D 中没有 const 或 volatile 类型修饰符。想要声明那些使用了这类类型修饰符的 C 函
数,则仅需要从声明中移除这些关键字即可。
• D 中的字符串不是以 0 结尾的。关于此点的更多信息,请参见“数据类型兼容
性”。但是,D 里的字符串文字是以 0 结尾的。
同样地,C 代码也可以调用 D 函数,只要 D 函数采用了同 C 编译器兼容的特性,多数情
况是 extern (C):
// myfunc() 可以被任何 C 函数调用
extern (C)
{
void myfunc(int a, int b)
{
...
}
}
107
第 5 章 C 语言接口 — 张雪平
5.2 存储分配
C 代码通过调用 malloc() 和 free() 显示地管理内存。D 使用 D 垃圾收集程序分配内存,所
以不需要显式地释放内存。
D 仍然可以使用 c.stdlib.malloc() 和 c.stdlib.free() 显式地分配和释放内存,可用于链接那些
需要 malloc 缓冲的 C 函数之类的情况。
如果指向来即收集程序分配的内存的指针被传递给 C 函数,必须确保这份内存不会在使用
它的 C 函数退出之前被内存收集程序回收。要达到这个目的,可以:
• 使用 c.stdlib.malloc() 创建一份数据的副本,把该副本传递给 C 函数。
• 将指针放在堆栈上(作为参数或者自动变量),因为垃圾收集程序会扫描堆栈。
• 将指向它的指针放在静态数据段,因为垃圾收集程序会扫描静态数据段。
• 使用 gc.addRoot() 或者 gc.addRange() 将指针交由垃圾收集程序管理。

[color=red]上面几处c.x.x 2.014中均改为 std.c.x.x[/color]

就算是指向所分配内存块内部的指针也足以让 GC 知道对象正在使用;也就是,不一定要需
要维护指向所分配内存开始处的指针。
垃圾收集程序不会扫描不是通过 D Thread 接口创建的线程的堆栈。也不会扫描其它 DLL
中的数据段等。


5.3 数据类型兼容性

[color=red]D And C Type Equivalence 2.014[/color]
D 类型 C 类型
void void
bit 无等价类型 [color=red] (2.014中无bit 类型)[/color]
byte signed char
ubyte unsigned char
char char (在 D 里 chars 是 unsigned)
wchar wchar_t (当 sizeof(wchar_t) 为 2 时)
dchar wchar_t (当 sizeof(wchar_t) 为 4 时)
short short
ushort unsigned short
int int
uint unsigned
long long long
ulong unsigned long long
float float
double double
real long double
ifloat float _Imaginary
idouble double _Imaginary
ireal long double _Imaginary
cfloat float _Complex
cdouble double _Complex
creal long double _Complex
struct struct
union union
enum enum
class 无等价类型
type* type *
type[dim] type[dim]
type[dim]* type(*)[dim]
type[] 无等价类型
type[type] 无等价类型

type function(parameters) type(*)(parameters)
type delegate(parameters) 无等价类型


对于大多数的 32 位 C 编译器来说,上述对应关系是成立的。C 标准并不约束类型的大小,
所以使用这种对应关系时要格外小心。


5.4 调用 printf()

主要的问题是 printf 格式指示符如何匹配对应的 D 数据类型。尽管按照设计,printf 只能处理以 0 结尾的字符串,不能处理 D 的char 动态数组,但事实证明,由于 D 动态数组的结构是{长度,指向数据的指针},printf 的 %.*s 格式工作的很好:
void foo(char[] string)
{
printf("my string is: %.*s\n", string);
}
机敏的读者会注意到 printf 格式字符串文字量并不以‘\0’结尾。这是因为如果字符串文字量
不是数据结构的初始值,就会在结尾处存储一个辅助的‘\0’。
有一个改进的 D 函数可以用于格式化输出,它就是 std.stdio.writef()。


5.5 结构和联合

D 的结构和联合同 C 中的相似。

C 代码通常使用命令行选项或者各种实现提供的 #pragma 指令指定结构的对齐或者紧缩方
式。D 支持与 C 编译器规则对应的显式的对齐特征。可以先查看 C 代码是如何对齐的,然
后据此显式地设置 D 结构的对齐方式。
D 不支持位域(bit field)。如有必要,则可以使用移位(shift)和屏蔽(mask)操作来进行模拟。[color=red]htod will convert bit fields to inline functions that do the right shift and masks. 1.024[/color]


[color=red]1.030
Interfacing to C++

D does not provide an interface to C++. Since D, however, interfaces directly to C, it can interface directly to C++ code if it is declared as having C linkage.
D class objects are incompatible with C++ class objects[/color]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值