forked from dlang/dlang.org
-
Notifications
You must be signed in to change notification settings - Fork 4
/
interfaceToC.dd
481 lines (381 loc) · 12.8 KB
/
interfaceToC.dd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
Ddoc
$(SPEC_S Cとのインターフェイス,
$(P D は、システムのCコンパイラと相性良く動作するように設計されています。
独自のVMを持ったりはせず、既存のCのランタイムライブラリを使うのです。
せっかく沢山のC APIが既に存在するというのに、それを D に移植したり
D 用のラッパを書いたり…という作業はばかげています。
直接Cの関数を呼び出せるというのは、なんと楽なことでしょうか。
)
$(P データ型やそのメモリ配置、関数の呼び出し規約をCコンパイラと合わせることで、
Cとの互換性が実現されています。
)
<h2>C の関数を呼び出す</h2>
$(P Cの関数はDから直接呼び出せます。
ラッパ関数や引数のすりあわせとか、
Cの関数を別のDLLに分けたりする必要は全くありません。
)
$(P Cの関数は呼び出し規約の指定付きで宣言します。大抵は "C"
呼び出し規約で問題ないでしょう。例えば:
)
------
extern (C) int strcmp(char* string1, char* string2);
------
$(P すると、Dのコードからは当たり前のように呼び出すことができます:)
------
import std.string;
int myDfunction(char[] s) {
return strcmp(std.string.toStringz(s), "foo");
}
------
$(P 何が起きているのかをもっと具体的に説明しますと:)
$(UL
$(LI Dコンパイラは、C の関数名がどのようにmangleされているのか、
またCの関数の正しい呼び出し/復帰手続きについて、把握しています。)
$(LI Cの関数を別の同名の
C関数でオーバーロードすることはできません。)
$(LI __cdecl や __far, __stdcall,
$(LINK2 http://www.digitalmars.com/ctg/ctgLanguageImplementation.html#declspec, __declspec),
などのCの
$(LINK2 http://www.digitalmars.com/ctg/ctgLanguageImplementation.html#extended, 拡張型修飾子)
は D にはありませんが、これは
$(D extern (C)) のように $(LINK2 $(WEBURL)attribute.html#linkage, リンケージ属性)
として処理されています。)
$(LI Dにはvolatile修飾子もありません。
volatileを使ったCの関数を宣言するには、単に宣言からこの予約語を取り除いてください。)
$(LI Dの文字列は0終端になっていません。
詳しくは "データ型の互換性" をご覧下さい。
ただし、文字列リテラルは0終端になっています。)
)
$(P extern (C) 属性などで
Cコンパイラと互換性があるようにコンパイルされた
D の関数なら、逆にCのコードからDの関数を呼び出すことも可能です:)
------
// myfunc() はCのどの関数からも呼び出せる
extern (C) {
void myfunc(int a, int b) {
...
}
}
------
<h2>メモリ割り当て</h2>
$(P C では
$(LINK2 http://www.digitalmars.com/rtl/stdlib.html#malloc, malloc()) や
$(LINK2 http://www.digitalmars.com/rtl/stdlib.html#free, free()) によって明示的にメモリを管理します。
一方 D ではガベージコレクタでメモリを割り当てるので、
明示的な free は不要です。
)
$(P mallocで確保されたバッファを要求するようなCの関数と連携するために、
D では c.stdlib.malloc() や c.stdlib.free() の呼び出しによって
明示的にメモリ管理を行うこともできます。
)
$(P Dのガベージコレクタで確保したメモリへのポインタを渡すには、
Cの関数がそのメモリを使い終わる前にガベージコレクタが領域を回収してしまう、
といった事故が起きないことを確かめなくてはなりません。
これは幾つかの方法で実現できます:
)
$(UL
$(LI c.stdlib.malloc() で確保した領域にデータをコピーし、
そちらを代わりに渡す。)
$(LI その領域へのポインタをスタック上(引数か、自動変数)に残しておく。
ガベージコレクタはスタック上のオブジェクトは生きていると判定します。)
$(LI その領域へのポインタを静的データ領域に残しておく。
ガベージコレクタは静的データ領域のオブジェクトは生きていると判定します。)
$(LI そのポインタを、
$(V1 std.gc.addRoot())
$(V2 $(LINK2 $(WEBURL)phobos/core_memory.html#addRoot, std.gc.addRoot()))
か
$(V1 std.gc.addRange())
$(V2 $(LINK2 $(WEBURL)phobos/core_memory.html#addRange, std.gc.addRange()))
によってガベージコレクタへ登録する。)
)
$(P オブジェクトがまだ使われていることを
GC に知らせるには、
割り当てられたメモリ領域の内部へのポインタがあれば十分です。
領域の先頭へのポインタを保持しておく必要はありません。
)
$(P Dによって作られた以外のスレッドのスタックや、
他のDLLに属するデータセグメントについては、
ガベージコレクタによって探索されません。
)
<h2>データ型の互換性</h2>
$(TABLE2 D と C の対応する型,
$(TR <th rowspan=2>D</th><th colspan=2>C</th>)
$(TR $(TH 32 bit) $(TH 64 bit))
$(TR
$(TD $(B void))
$(TD2 $(B void))
)
$(TR
$(TD $(B byte))
$(TD2 $(B signed char))
)
$(TR
$(TD $(B ubyte))
$(TD2 $(B unsigned char))
)
$(TR
$(TD $(B char))
$(TD2 $(B char) (Dではcharはunsignedです))
)
$(TR
$(TD $(B wchar))
$(TD2 $(B wchar_t) (sizeof(wchar_t) が 2 のとき))
)
$(TR
$(TD $(B dchar))
$(TD2 $(B wchar_t) (sizeof(wchar_t) が 4 のとき))
)
$(TR
$(TD $(B short))
$(TD2 $(B short))
)
$(TR
$(TD $(B ushort))
$(TD2 $(B unsigned short))
)
$(TR
$(TD $(B int))
$(TD2 $(B int))
)
$(TR
$(TD $(B uint))
$(TD2 $(B unsigned))
)
$(V1
$(TR
$(TD $(B long))
$(TD $(B long long))
$(TD $(B long))
)
$(TR
$(TD $(B ulong))
$(TD $(B unsigned long long))
$(TD $(B unsigned long))
)
)
$(V2
$(TR
$(TD $(B c_long (core.stdc.config で定義)))
$(TD $(B long))
$(TD $(B long))
)
$(TR
$(TD $(B c_ulong (core.stdc.config で定義)))
$(TD $(B unsigned long))
$(TD $(B unsigned long))
)
$(TR
$(TD $(B long))
$(TD $(B long long))
$(TD $(B long (または long long)))
)
$(TR
$(TD $(B ulong))
$(TD $(B unsigned long long))
$(TD $(B unsigned long (または unsigned long long)))
)
)
$(TR
$(TD $(B float))
$(TD2 $(B float))
)
$(TR
$(TD $(B double))
$(TD2 $(B double))
)
$(TR
$(TD $(B real))
$(TD2 $(B long double))
)
$(V1
$(TR
$(TD $(B ifloat))
$(TD2 $(B float _Imaginary))
)
$(TR
$(TD $(B idouble))
$(TD2 $(B double _Imaginary))
)
$(TR
$(TD $(B ireal))
$(TD2 $(B long double _Imaginary))
)
$(TR
$(TD $(B cfloat))
$(TD2 $(B float _Complex))
)
$(TR
$(TD $(B cdouble))
$(TD2 $(B double _Complex))
)
$(TR
$(TD $(B creal))
$(TD2 $(B long double _Complex))
)
)
$(TR
$(TD $(B struct))
$(TD2 $(B struct))
)
$(TR
$(TD $(B union))
$(TD2 $(B union))
)
$(TR
$(TD $(B enum))
$(TD2 $(B enum))
)
$(TR
$(TD $(B class))
$(TD2 なし)
)
$(TR
$(TD $(I type)$(B *))
$(TD2 $(I type) $(B *))
)
$(TR
$(TD $(I type)$(B [)$(I dim)$(B ]))
$(TD2 $(I type)$(B [)$(I dim)$(B ]))
)
$(TR
$(TD $(I type)$(B [)$(I dim)$(B ]*))
$(TD2 $(I type)$(B (*)[)$(I dim)$(B ]))
)
$(TR
$(TD $(I type)$(B []))
$(TD2 なし)
)
$(TR
$(TD $(I type)$(B [)$(I type)$(B ]))
$(TD2 なし)
)
$(TR
$(TD $(I type) $(B function)$(B $(LPAREN))$(I parameters)$(B $(RPAREN)))
$(TD2 $(I type)$(B (*))$(B $(LPAREN))$(I parameters)$(B $(RPAREN)))
)
$(TR
$(TD $(I type) $(B delegate)$(B $(LPAREN))$(I parameters)$(B $(RPAREN)))
$(TD2 なし)
)
$(TR
$(TD $(B size_t))
$(TD2 $(B size_t))
)
$(TR
$(TD $(B ptrdiff_t))
$(TD2 $(B ptrdiff_t))
)
)
$(P の対応関係はほとんどの C コンパイラで成り立ちます。ただし
Cの標準では型のサイズは一意に定められていないので、注意が必要です。
)
$(V2
<h2>Dの配列をCの関数に渡す</h2>
$(P Cでは、例え関数プロトタイプでは配列であるかのように宣言されていたとしても、
配列はポインタとして渡されます。Dでは、静的配列は参照渡しではなく、値渡しされます。
従って、
関数プロトタイプはCの期待するものになっているように調整する必要があります。)
$(TABLE2 D と C の同等な関数プロトタイプ,
$(TR
$(TH D の型)
$(TH C の型)
)
$(TR
$(TD $(I T)$(B *))
$(TD $(I T)$(B []))
)
$(TR
$(TD $(B ref) $(I T)$(B [)$(I dim)$(B ]))
$(TD $(I T)$(B [)$(I dim)$(B ]))
)
)
$(P 例えば:)
$(CCODE
void foo(int a[3]) { ... } // C のコード
)
---
extern (C)
{
void foo(ref int[3] a); // D でのプロトタイプ宣言
}
---
)
<h2>printf() の呼び出し</h2>
$(P これは主に、
$(LINK2 http://www.digitalmars.com/rtl/stdio.html#printf, printf のフォーマット指定)
がDのデータ型と合うかどうか、
が問題になります。printf はNUL終端の文字列を扱うようになっていますが、
Dでのcharの動的配列はそうなっていません。
しかし配列データの前に
4バイトで配列のサイズが置かれていますので、$(D %.*s) を使うと動作します:
)
------
void foo(char[] string) {
printf("my string is: %.*s\n", string.length, string.ptr);
}
------
$(P 例の $(CODE printf) のフォーマット文字列リテラルは $(CODE '\0')
で終わっていません。これは、
より大きな構造体の初期化子の一部でない限り、
文字列リテラルの後ろには
$(CODE '\0') が格納されるようになっているためです。
)
$(P 書式化出力を得るためのDでのベターな関数として、
$(CODE std.stdio.writef()) があります。
)
<h2>構造体と共用体</h2>
$(P Dの構造体と共用体は、Cのそれとほぼ同じです。
)
$(P >Cのコードでは、実装特有の#pragmaやコンパイラのコマンドスイッチによって、
構造体の整列を制御します。これに対応するものとして、D には
明示的なアラインメント属性が用意されています。
C側でのアラインメントを調べて、
D側の構造体宣言に明示的にその値を設定して下さい。
)
$(P Dはビットフィールドをサポートしません。必要ならば、
シフトとビットマスク演算によってエミュレートできます。
$(LINK2 phobos/std_bitmanip.html#bitfields, std.bitmanip.bitfields)
というライブラリ型もあります。
$(DPLLINK htod.html, htod) を使うと、
ビットフィールドはシフトとマスクを使ったインライン関数に変換されます。
)
<h2>$(LNAME2 Using C Libraries, 既存の C ライブラリを使う)</h2>
$(P D からは C のコードを直接呼び出せるので、どんな C のライブラリ関数でも、
D とリンクすれば呼び出すことができます。
これをするには、しかし、D インターフェイス (.di) ファイルを、
そのライブラリの C の .h ヘッダファイルから変換して作る必要があります。
)
$(P 著名な C のライブラリに関しては、まずは対応する D のインターフェイスファイルがないか、
$(LINK2 https://github.com/D-Programming-Deimos/, Deimos プロジェクト) をチェックしましょう。
それがまだ存在せず、あなたが書き上げたならば、ぜひ、
Deimos プロジェクトに貢献してください。.
)
<h2>$(LNAME2 C Globals, C のグローバル変数へのアクセス)</h2>
$(P C のグローバル変数は D から直接アクセスできます。C のグローバル変数は
C の命名規約に従うので、D からは $(D extern (C)) ブロックで宣言される必要があります。
$(D extern) 記憶域クラスを指定することで、そのグローバル変数が D のコードではなく
C のコードの側で割り当てられていることを処理系に伝えます。
$(V2 C のグローバル変数は、デフォルトではスレッドローカルではなく、グローバルな記憶域に配置されます。
グローバル記憶域を D から参照するには、
$(D __gshared) 記憶域クラスを使います。)
)
---
extern (C) extern __gshared int x;
---
$(V1
<hr>
<h1>C++とのインターフェイス</h1>
$(P D は C++ とのインターフェイスを
$(DPLLINK COM.html, COM によるもの) 以外特に提供しません。
しかしながら、D は C と直接やりとりできるため、
C のリンケージを持つよう宣言された C++ コードとはやりとりが可能です。
)
$(P D のクラスオブジェクトはC++のクラスオブジェクトとは互換性がありません。
)
)
)
Macros:
TD2=<td colspan=2>$0</td>
TITLE=Cとのインターフェイス
WIKI=InterfaceToC
CATEGORY_SPEC=$0