1

const(およびin)

C関数があると考えてください:

unsigned int foo(const unsigned int a);

constコードが でコンパイルに合格するかのように、生成されたコードには影響しconstません。そうでない場合は何も壊れないconstため、C コンパイラはコンパイル時にコード コントラクト指定子としてのみ使用します。

uint foo(in uint a);Dでこの関数を書いたりuint foo(const uint a);呼び出したりする努力はありますか? これは、D コンパイラが を呼び出すためのより効率的なコードを生成するのに役立ちfooますか? それとも (少なくとも値型の引数に対して) 効果がありませんか?

refout

C関数あり

unsigned int bar(unsigned int *a);

uint bar(uint* a);これを D に変換するときにポインター構文を使用する義務がありますか、それともuint bar(ref uint a);(またはuint bar(out uint a);、それが出力専用であることがわかっている場合aは、のドキュメントからbar) 書くことができますか? refとの下に追加の隠れた機構がありoutますか、それとも見た目のように単純なポインタにすぎませんか? out呼び出しが D のスコープ外に出た場合、D はパラメーターをデフォルト値に初期化するための「グルー コード」を生成しますか?

Update1:ref s とs が引数でどのように処理されるかをテストするための簡単なコードを書きました。out実際には、少なくともints の場合は単純なポインターのように見えますがout、渡されたときに初期値にリセットされません。C 側はその値を読み取って変更できます。のように効果的に機能しrefます。このように使用するときに GC 関連の問題が発生する可能性があるかどうかはわかりません。

Update2:ref関数の結果でポインターの代わりに使用することも期待どおりに機能します。constはまだテストされておらず、プログラムを逆アセンブルせずにチェックする方法がわかりません。

4

2 に答える 2

1

C はパラメーターをマングルしないため、すべての型修飾子にリンクされます。

extern(C) 関数プロトタイプで宣言された D 型修飾子が実際に C 関数の動作と一致することを確認するのは、プログラマの責任です。

C には参照が存在しないため、ref や C コードでの ref は使用しません。世界)。

編集:定数について。C の const と D の const は同じものではありません (D では推移的ですが、C ではありません)。この場合も、関数のパラメーターを D セマンティックに従って const 修飾できるかどうかを判断するのはプログラマーです。

于 2012-04-06T21:40:51.143 に答える
1

in(これは と同じですconst scope) は C に存在しないため、C にはscope存在しません。またout、andrefも C にも存在しません。関数では使用しないでくださいextern(C)。関数のパラメーターのように使用すると、コンパイラーはおそらくエラーを出すはずですextern(C)が、そうでない場合でも驚くことではありません。たまたまうまくいったら、あなたはただの「幸運」です。いつでも動作を停止する可能性があります。どのようrefout実装されているかは、コンパイラの実装の詳細です。一般に、実際に C に存在する関数に対してのみ修飾子を使用する必要がありますextern(C)。D のコンパイラは、関数に対して D の機能を動作させる魔法を行うつもりはありませんextern(C)extern(C)

私が知っている唯一の 2 つの例外は と です。pureこれらnothrowは呼び出し規則にまったく影響しないため、D が特定の関数から呼び出すことができるかどうかだけです。pureしたがって、C 関数をand/orとしてマークできますnothrow。ただし、 でマークする場合は、関数が実際に純粋であることを確認する必要がありますpure(そうしないと、厄介なバグが発生する可能性があります) nothrow。技術的には、@safe、@trusted、および @system も使用できますが、C 関数は C 関数であるため、実際にはデフォルトの @system のままにしておく必要があります。

いいえ、パラメータを C 関数にマークしconstても、最適化に役立つ可能性はほとんどありません。パラメータが値型の場合const、呼び出し元の観点からは意味がありません。引数は関係なくコピーされます。参照型でのみ重要です。の場合extern(C)、それはポインターとポインターを含む構造体に限定されます (直接または間接的に)。そこにはいくつかの最適化があるかもしれませんが、私はそれに賭けません-特にdmdでは、一般的にコードだけでなくgdcやldcも最適化されません. せいぜい、コンパイラができることは、その呼び出しの後、渡された変数が変更されていないことを判断することです。これにより、呼び出し元内で他の最適化が可能になる可能性がありますが、呼び出し元とコンパイラに大きく依存します。

さらに重要なのは、C パラメータが実際に であるかどうかconstです。const一般的には問題ありませんが、C では変数をキャスト アウェイして変更することは合法ですが、D ではそうではありません。これが主に懸念される可能性があるのは、immutableデータに関するものです (文字列リテラルが主な例です)。何かが実際にデータを変更しようとすると、セグメンテーション違反またはさらに悪化するリスクがあります。一般に、それはマークされている C 関数のパラメーターでは問題にならないはずですがconst(場合によってはそうなる可能性があります)、C がマークされていないパラメーターをマークすることconstは、ほぼ間違いなく悪い考えであることを意味します。その場合、変数の値が C 関数によって実際に変更されないようにする必要があります。なぜなら、あなたがそれをconstC関数がそれを変更すると、バグが発生します。

したがって、要約すると、一般的に、extern(C)D 固有のものではなく、C 修飾子でのみ関数をマークする必要がありますconst。 C関数が実際に何であるかを知っているならpure、それを とマークすることができますpure。実際に であることがわかっている場合はnothrow、 でマークできますnothrow。また、パラメーターが C 関数によって決して変更されないことがわかっている場合は、それを としてマークできますconst。しかし、それについては非常に保守的である必要があります。そうしないと、コードに厄介なバグが発生します。

まだ読んでいない場合は、これらのページを読んでください。

http://dlang.org/interfaceToC.html
http://dlang.org/htomodule.html

于 2012-04-06T22:37:18.067 に答える