D 1.0   D 2.0
About Japanese Translation

Last update Sat Mar 6 18:04:39 2010

Cとのインターフェイス

D は、システムのCコンパイラと相性良く動作するように設計されています。 独自のVMを持ったりはせず、既存のCのランタイムライブラリを使うのです。 せっかく沢山のC APIが既に存在するというのに、それを D に移植したり D 用のラッパを書いたり…という作業はばかげています。 直接Cの関数を呼び出せるというのは、なんと楽なことでしょうか。

データ型やそのメモリ配置、関数の呼び出し規約をCコンパイラと合わせることで、 Cとの互換性が実現されています。

C の関数を呼び出す

Cの関数はDから直接呼び出せます。 ラッパ関数や引数のすりあわせとか、 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");
}

何が起きているのかをもっと具体的に説明しますと:

extern (C) 属性などで Cコンパイラと互換性があるようにコンパイルされた D の関数なら、逆にCのコードからDの関数を呼び出すことも可能です:

// myfunc() はCのどの関数からも呼び出せる
extern (C)
{
    void myfunc(int a, int b)
    {
	...
    }
}

メモリ割り当て

C では、malloc() や free() によって明示的にメモリを管理します。 一方 D ではガベージコレクタでメモリを割り当てるので、 明示的な free は不要です。

mallocで確保されたバッファを要求するようなCの関数と連携するために、 D では c.stdlib.malloc() や c.stdlib.free() の呼び出しによって 明示的にメモリ管理を行うこともできます。

Dのガベージコレクタで確保したメモリへのポインタを渡すには、 Cの関数がそのメモリを使い終わる前にガベージコレクタが領域を解放してしまう、 といった事故が起きないことを確かめなくてはなりません。 これは幾つかの方法で実現できます:

オブジェクトがまだ使われていることを GC に知らせるには、 割り当てられたメモリ領域の内部へのポインタがあれば十分です。 領域の先頭へのポインタを保持しておく必要はありません。

Dによって作られた以外のスレッドのスタックや、 他のDLLに属するデータセグメントについては、 ガベージコレクタによって探索されません。

データ型の互換性

D と C の対応する型
D の型C の型
32 bit 64 bit
void void
byte signed char
ubyte unsigned char
char char (Dではcharは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 long
ulong unsigned long 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 &
type[dim] type[dim]
type[dim]* type(*)[dim]
type[] なし
type[type] なし
type function(parameters) type(*)(parameters)
type delegate(parameters) なし
size_t size_t
ptrdiff_t ptrdiff_t

この対応関係はほとんどの32bit C コンパイラで成り立ちます。ただし Cの標準では型のサイズは一意に定められていないので、注意が必要です。

printf() の呼び出し

これは主に、printf のフォーマット指定がDのデータ型と合うかどうか、 が問題になります。printf はNUL終端の文字列を扱うようになっていますが、 Dでのcharの動的配列はそうなっていません。 しかし配列データの前に 4バイトで配列のサイズが置かれていますので、%.*s を使うと完璧に動作します:

void foo(char[] string)
{
    printf("my string is: %.*s\n", string);
}

例の printf のフォーマット文字列リテラルは \0 で終わっていません。これは、 より大きな構造体の初期化子の一部でない限り、 文字列リテラルの後ろには \0 が格納されるようになっているためです。

書式化出力を得るためのDでのベターな関数として、 std.stdio.writef() があります。

構造体と共用体

Dの構造体と共用体は、Cのそれとほぼ同じです。

Cのコードでは、実装特有の#pragmaやコンパイラのコマンドスイッチによって、 構造体の整列を制御します。これに対応するものとして、D には 明示的なアラインメント属性が用意されています。 C側でのアラインメントを調べて、 D側の構造体宣言に明示的にその値を設定して下さい。

Dはビットフィールドをサポートしません。必要ならば、 シフトとビットマスク演算によってエミュレートできます。 htod は、 ビットフィールドを右シフトとマスクを使ったinline関数に変換します。


C++とのインターフェイス

DはC++とのインターフェイスは提供しません。しかし、D は C とのインターフェイスを備えているので、C++ のコードが C のリンケージでコンパイルされていれば、直接リンクすることが出来ます。

DのクラスオブジェクトはC++のクラスオブジェクトとは互換性がありません。