英語版
このページの英語版を見る

プラグマ

PragmaDeclaration:
    Pragma ;
    Pragma DeclarationBlock
PragmaStatement: Pragma ; Pragma NoScopeStatement
Pragma: pragma ( Identifier ) pragma ( Identifier , ArgumentList )

プラグマは特別な情報を実装に渡す ベンダ固有の拡張を追加することができる。 プラグマは、; 、 で終了し、文、文のブロック、宣言、宣言のブロックに適用できる。 宣言のブロックに適用できる。

プラグマはPragmaDeclarationまたはPragmaStatementのどちらかになる。 またはPragmaStatementである。

pragma(ident);        // それ自体で

pragma(ident) declaration; // ある宣言に影響を与える

pragma(ident): // その後の宣言に影響を与える
    declaration;
    declaration;

pragma(ident)   // 宣言のブロックに影響を与える
{
    declaration;
    declaration;
}

pragma(ident) statement; // 1つの文に影響を与える

pragma(ident)   // ステートメントのブロックに影響を与える
{
    statement;
    statement;
}

プラグマの種類はIdentifierによって決定される。 ArgumentListはカンマで区切られた カンマ区切りのリストである。AssignExpressionsは 式として解析可能でなければならない。 は個々のプラグマのセマンティクスに依存する。

定義済みプラグマ

すべての実装は、たとえ無視するとしても、これらをサポートしなければならない:

実装定義: 実装はこれらのプラグマを無視してもよい。

pragma crt_constructor

Cランタイム・ライブラリが初期化された後、Dランタイム・ライブラリが初期化される前に実行されるように関数を注釈する。 Dランタイム・ライブラリが初期化される前に実行されるようにする。

その関数は以下のものでなければならない:

  1. 以下でなければならない。extern (C)
  2. パラメータを持たない。
  3. 非静的メンバ関数でないこと。
  4. 宣言ではなく、関数定義であること(すなわち、関数本体を持たなければならない)。
  5. デストラクタを持つ型を返さない。
  6. ネストされた関数であってはならない。
__gshared int initCount;

pragma(crt_constructor)
extern(C) void initializer() { initCount += 1; }

プラグマに対する引数は許されない。

関数は、以下の両方のアノテーションを持つことができる。pragma(crt_constructor)pragma(crt_destructor) の両方を付けることができる。

関数定義以外の宣言にアノテーションを付けても効果はない。

構造体またはクラス定義にアノテーションを付けても、集合体のメンバには影響しない。 のメンバには影響しない。

pragma(crt_constructor) でアノテーションされた関数は、変数を初期化することができる。 const またはimmutable

ベストプラクティス: システム・プログラミングやC/C++とのインターフェイスに使用する、 例えば、DSOをロードするときにランタイムを初期化できるようにする、 の単純な置き換えとして使用する。 shared static this 単純な置き換えとして使用する。
実装定義: でアノテーションされた関数の実行順序は、実装によって定義される。 でアノテーションされた関数の実行順序は実装で定義される。 pragma(crt_constructor)
ベストプラクティス: つのモジュール内で関数が呼び出される順番を制御するには、次のように記述する。 を書き、その関数のみにアノテーションを付ける。
実装定義: これは、Cコンパイラが。 これは、Cコンパイラが 。C++コンパイラーは、静的な コンストラクタとデストラクタを実行するために使う。 例えば、GCCのmain() __attribute__((constructor)) がそれに相当する。 Digital Mars Cでは、crt_constructorとcrt_destructor関数をマークするために、_STI_STD 識別子の接頭辞を使用している。
実装定義: 注釈付き関数への参照は、Elfシステムでは セクションに挿入される。 Elf システムの場合は、.init_array セクションに挿入される、 Win32 OMFシステム用のXI 、 Windows MSCOFFシステム用の.CRT$XCU 、 およびOSXシステム用の__mod_init_func
注釈: crt_constructorcrt_destructor は、v2.078.0 (2018)で実装された。 v2.078.0 (2018-01-01). 一部のコンパイラーは、それ以前に非標準のコンパイラー固有のメカニズムを公開していた。

pragma crt_destructor

pragma(crt_destructor) は、 と同じ働きをする:pragma(crt_constructor)

  1. Dランタイム・ライブラリが終了した後、Cランタイム・ライブラリが終了する前に "関数"が実行されるように注釈を付ける。 Dランタイム・ライブラリが終了した後、Cランタイム・ライブラリが終了する前に実行されるように関数をアノテーションする。 Cのexit() 関数を呼び出すと、注釈付き関数も実行される。
  2. アノテーションされた関数が実行される順序は、 でアノテーションされた関数の順序と逆になる。 pragma(crt_constructor) でアノテーションされた関数とは逆の順序で実行される。
実装定義: これは、Cコンパイラが、 がリターンした後、または がリターンした後にコードを実行するために使用するメカニズムである。 これは、 が戻るか、 が呼び出された後にコードを実行するために、Cコンパイラが使用するメカニズムである。C++コンパイラーは、静的な デストラクタを実行するために使う。 例えば、GCCのmain() exit() __attribute__((destructor)) がそれに相当する。 Digital Mars Cでは、_STI_STD 識別子プレフィックスを使って、crt_constructorとcrt_destructor関数をマークしている。
実装定義: 注釈付き関数への参照は、Elfシステムでは セクションに挿入される。 Elf システムの場合は、.fini_array セクションに挿入される、 Win32 OMFシステム用のXC 、 Windows MSCOFFシステム用の.CRT$XPU 、 およびOSXシステム用の__mod_term_func
__gshared int initCount;

pragma(crt_constructor)
extern(C) void initialize() { initCount += 1; }

pragma(crt_destructor)
extern(C) void deinitialize() { initCount -= 1; }

pragma(crt_constructor)
pragma(crt_destructor)
extern(C) void innuendo() { printf("Inside a constructor... Or destructor?\n"); }

pragma inline

関数がインライン化されるかどうかに影響する。宣言レベルであれば 宣言レベルの場合、ブロック内で宣言された関数に影響する。関数の内部にある場合は、その関数に影響する。 関数の内部にある場合、その関数に影響する。

2つの形式がある:

  1. pragma(inline)
    
    実装のデフォルトの動作と一致するように動作を設定する。
  2. pragma(inline, AssignExpression)
    
    AssignExpressionは評価され、booleanに変換できる型を持っていなければならない。 に変換できる型を持っていなければならない。 結果がfalseの場合、関数はインライン化されず、そうでない場合は常にインライン化される。

複数のAssignExpression を指定することはできない。

1つの関数内に複数のプラグマ・インラインがある場合、レキシカルに最後のものが有効になる、 レキシカルに最後のものが有効になる。

pragma(inline):
int foo(int x) // foo()は決してインライン化されない
{
    pragma(inline, true);
    ++x;
    pragma(inline, false); // 他より優先される
    return x + 3;
}
実装定義:
  1. デフォルトのインライン動作は通常、コンパイラ・スイッチで選択できる。 -inlineなどで選択できる。
  2. 特定の関数がインライン化できるかどうかは実装で定義される。
  3. 関数がインライン化できない場合、pragma(inline, true) 。 エラーメッセージが典型的である。

pragma lib

AssignExpressionは1つで、コンパイル時に文字列リテラルに評価されなければならない。

pragma(lib, "foo.lib");
実装定義: 文字列リテラルは、ライブラリ・ファイルのファイル名を指定する。この名前 生成されるオブジェクト・ファイルに挿入されるか、リンカに渡される、 リンカは自動的にそのライブラリをリンクする。

pragma linkerDirective

AssignExpressionは1つで、コンパイル時に文字列リテラルに評価されなければならない。

pragma(linkerDirective, "/FAILIFMISMATCH:_ITERATOR_DEBUG_LEVEL=2");
実装定義: 文字列リテラルは、生成されるオブジェクト・ファイルに埋め込まれるリンカ指令を指定する。 リンカ指令は、MS-COFF 出力でのみサポートされている。

pragma mangle

シンボルのデフォルトのマングリングを上書きする。

変数と関数の場合、AssignExpressionは1つでなければならず、コンパイル時に文字列リテラルに評価されなければならない。 集約には1つまたは2つのAssignExpressionがあり、1つはコンパイル時に文字列リテラルとして評価され、もう1つはシンボルとして評価されなければならない。 シンボルに評価されなければならない。そのシンボルがTemplateInstanceの場合、集約はテンプレートとして扱われる。 として扱われる。文字列が与えられない場合は、シンボルの識別子が使われる。 集約の名前がDキーワードの場合、両方の引数を使用することができる。

これは、関数と変数のシンボルにのみ適用される。その他のシンボルは無視される。

実装定義: macOSおよびWin32では、文字列の前にアンダースコア( )が付加される。 が付加される。これにより、すべての互換性のある これにより、特殊大文字にする代わりに、互換性のある(ある場合はPOSIX、別の場合はwin64)すべてのプラットフォームで同じものを使うことができる。 _ pragma(mangle)
根拠:
  • Dが表現できないシンボル名へのリンクを可能にする。
  • Dキーワードであるシンボルへのリンクを可能にする。 はキーワードになり得ないからである。
pragma(mangle, "body")
extern(C) void body_func();
pragma(mangle, "function")
extern(C++) struct _function {}
template ScopeClass(C)
{
    pragma(mangle, C.stringof, C)
    struct ScopeClass { align(__traits(classInstanceAlignment, C)) void[__traits(classInstanceSize, C)] buffer; }
}
extern(C++)
{
    class MyClassA(T) {}
    void func(ref ScopeClass!(MyClassA!int)); // MyClass<int>&としてマングルされる
}

pragma msg

それぞれのAssignExpressionはコンパイル時に評価され、その後、すべてが1つのメッセージにまとめられる。

pragma(msg, "compiling...", 6, 1.0); // コンパイル時に"compiling...61.0"と表示される
実装定義: メッセージはどのような形で、どのようにユーザーに表示されるのか。 1つの方法は、標準エラー・ストリームに出力することである。
根拠: writeln() 、実行時に情報メッセージを書く役割を果たすのと似ている、 はコンパイル時に同等の役割を果たす。 例: pragma(msg)
static if (kilroy)
    pragma(msg, "Kilroy was here");
else
    pragma(msg, "Kilroy got lost");

pragma printf

pragma(printf) は、関数宣言がprintfライクな関数であることを指定する。 つまり、 または 関数であり、 パラメータが以下を受け付ける。 へのポインタを持つ 関数であることを意味する。 "可変長引数リストまたは "型パラメータを最後のパラメータとする。 extern (C) extern (C++) format char ... va_list

引数format が文字列リテラルである場合、それがC99標準に従って有効な書式文字列であることが検証される。 であることが検証される。format パラメータの後に... が続く場合、可変引数の数と型がチェックされる。 可変長引数の数と型が書式文字列と照合される。

診断される非互換性は以下の通りである:

C99規格では、余分な引数は無視される。

無視されるミスマッチは以下の通りである:

printf("%k\n", value); // エラー: 非標準書式 k
printf("%d\n");        // エラー: 引数が足りない
printf("%d\n", 1, 2);  // OK、余分な引数は無視される
ベストプラクティス: 非標準のprintf/scanf書式を使用するには、簡単な回避策がある:
const format = "%k\n";
printf(format.ptr, value);  // エラーなし
ベストプラクティス: 検出されたエラーのほとんどは移植性の問題である。例えば
string s;
printf("%.*s\n", s.length, s.ptr);
printf("%d\n", s.sizeof);
ulong u;
scanf("%lld%*c\n", &u);
と置き換えるべきである:
string s;
printf("%.*s\n", cast(int) s.length, s.ptr);
printf("%zd\n", s.sizeof);
ulong u;
scanf("%llu%*c\n", &u);

pragma(printf) 関数でない宣言に適用されたものは無視される。 特に、関数型へのポインタの宣言には効果がない。

pragma scanf

pragma(scanf) 関数宣言がscanfライクな関数であることを指定する。 つまり、 パラメータを持つ または 関数である。 へのポインタを持つ 関数であることを意味する。 の可変長引数リストか、 型のパラメータを最後のパラメータとする。 format extern (C) extern (C++) char ... va_list

引数format が文字列リテラルである場合、それがC99標準に従って有効な書式文字列であることが検証される。 であることが検証される。format パラメータの後に... が続く場合、可変引数の数と型がチェックされる。 可変長引数の数と型が書式文字列と照合される。

診断される非互換性は以下の通りである:

C99標準では、余分な引数は無視される。

pragma(scanf) 関数でない宣言に適用された引数は無視される。 特に、関数型へのポインタの宣言には効果がない。

pragma startaddress

AssignExpressionは1つで、コンパイル時に関数シンボルとして評価されなければならない。

実装定義: 関数シンボルはプログラムの開始アドレスを指定する。 このシンボルはオブジェクト・ファイルに挿入されるか、またはリンカに提示されて開始アドレスを設定する。 開始アドレスを設定する。 これは通常、アプリケーション・レベルのプログラミングには使われない、 これはアプリケーション・レベルのプログラミングには使われないが、特殊なシステム作業のために使われる。 アプリケーション・コードの場合、開始アドレスはランタイム・ライブラリによって管理される。 ランタイム・ライブラリによって処理される。
void foo() { ... }
pragma(startaddress, foo);

ベンダー固有のプラグマ

ベンダー固有のプラグマ識別子を定義することができる。 ベンダーの商標名が前置されている場合は、バージョン識別子と同様に定義できる。 バージョン識別子と同様である:

pragma(DigitalMars_extension) { ... }

実装は、認識できないプラグマについてはエラーを診断しなければならない、 実装は、たとえそれがベンダー固有のものであっても、認識できないプラグマについてはエラーを診断しなければならない。

実装定義: ベンダー固有のプラグマ
ベストプラクティス: ベンダー 固有のプラグマはバージョン文に包まれなければならない。
version (DigitalMars)
{
    pragma(DigitalMars_extension)
    {   ... }
}