型、演算子および式
Dには、各種のデータ・オブジェクトにアクセスして操作できる機能があります。具体的には、変数やデータ構造の作成または変更、OSカーネルやユーザー・プロセスで定義されているデータ・オブジェクトへのアクセス、整数定数、浮動小数点定数、文字列定数の宣言などを実行できます。 Dには、オブジェクトの操作や複合式の作成に使用されるANSI C演算子のスーパーセットが用意されています。 この項では、型、演算子および式のルールの詳細セットについて説明します。
識別子名およびキーワード
D識別子名は、大文字と小文字、数字およびアンダースコアで構成され、先頭の文字は英字またはアンダースコアである必要があります。 先頭文字が下線(_)の識別子名はすべて、Dシステム・ライブラリ用に予約されています。 これらの名前はDプログラム内での使用を避けてください。 通常、Dプログラマは、変数には大文字の名前を、定数にはすべて大文字の名前を使用します。
D言語キーワードは、プログラミング言語の構文自体で使用するために予約されている特別な識別子です。 これらの名前は常に小文字で指定され、D変数名には使用できません。 次の表に、D言語で使用するために予約されているキーワードを示します。
表4-2 Dキーワード
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dでは、ANSI Cキーワードのスーパーセットがキーワードとして予約されています。 D言語が将来使用するために予約されているキーワードは、*でマークされます。 将来の使用のために予約されているキーワードを使用しようとすると、Dコンパイラは構文エラーを生成します。 Dによって定義されるがANSI Cによって定義されないキーワードは、+でマークされます。 Dには、ANSI Cの型および演算子の完全セットが用意されています。 Dプログラミングの主な違いは、制御フロー構造体が存在しない点です。 ANSI Cの制御フローに関連付けられたキーワードは、Dで将来使用するために予約されています。
データ型およびサイズ
Dには、整数および浮動小数点の定数の基本データ型があります。 算術演算は、Dプログラム内の整数に対してのみ実行可能です。 Dでは、データ構造を初期化するために浮動小数点定数を使用できますが、浮動小数点算術演算の使用は許可されていません。 Dには、プログラムの作成に使用する64ビットのデータ・モデルが用意されています。
次の表に、64ビットのデータ・モデルの整数型名とサイズを示します。 整数は、常にシステム・ネイティブのバイト・エンコーディング順序で2の補数形式で表されます。
表4-3 D整数データ型
| 型名 | 64ビットのサイズ |
|---|---|
|
|
1バイト |
|
|
2バイト |
|
|
4バイト |
|
|
8バイト |
|
|
8バイト |
整数型(charを含む)の前には、signedまたはunsigned修飾子を付けられます。 unsigned修飾子の指定がない場合、整数は暗黙的にsignedになります。 Dコンパイラには、次の表に示す型の別名も用意されています。
表4-4 D整数型別名
| 型名 | 説明 |
|---|---|
|
|
1バイトの符号付き整数 |
|
|
2バイトの符号付き整数 |
|
|
4バイトの符号付き整数 |
|
|
8バイトの符号付き整数 |
|
|
ポインタと同じサイズの符号付き整数 |
|
|
1バイトの符号なし整数 |
|
|
2バイトの符号なし整数 |
|
|
4バイトの符号なし整数 |
|
|
8バイトの符号なし整数 |
|
|
ポインタと同じサイズの符号なし整数 |
これらの型の別名は、前の表にリストされている対応するベース型の名前を使用することと同等であり、データ・モデルごとに適切に定義されます。 たとえば、uint8_t型の名前は、符号なしchar型の別名です。
ノート:
事前定義された型の別名は、プリプロセッサによって含められるファイルでは使用できません。
Dの浮動小数点型は、ANSI Cの宣言および型と互換性があります。 Dでは、浮動小数点演算子はサポートされていませんが、浮動小数点型データ・オブジェクトのトレースとprintf関数によるフォーマットができます。 次の表に示す浮動小数点型を使用できます。
表4-5 D浮動小数点データ型
| 型名 | 64ビットのサイズ |
|---|---|
|
|
4バイト |
|
|
8バイト |
|
|
16バイト |
Dには、ASCII文字列を表す特殊なstring型も用意されています。 文字列の詳細は、「DTraceの文字列処理」を参照してください。
定数
整数定数は、10進数(12345)、8進(012345)または16進(0x12345形式で記述できます。 8進法(base 8)の定数には、接頭辞として0を付ける必要があります。 16進法(base 16)の定数には、接頭辞として0xまたは0Xを付ける必要があります。 整数定数には、その値を表す型として、int、longおよびlong longのうち最も小さい型が割り当てられます。 値が負である場合、型の符号付きバージョンが使用されます。 値が正で、符号付きの型で表すには値が大きすぎる場合は、符号なしの型が使用されます。 次の表に示すいずれかの接尾辞を任意の整数定数に適用して、そのDの型を明示的に指定できます。
| 接尾辞 | Dの型 |
|---|---|
|
|
コンパイラによって選択された型の |
|
|
|
|
|
|
|
|
|
|
|
|
浮動小数点定数は常に10進形式で書き込まれ、小数点(12.345)または指数(123e45)あるいはその両方( 123.34e-5)のいずれかを含む必要があります。 浮動小数点定数には、デフォルトでdouble型が割り当てられます。 次の表に示すいずれかの接尾辞を任意の浮動小数点定数に適用して、そのDの型を明示的に指定できます。
| 接尾辞 | Dの型 |
|---|---|
|
|
|
|
|
|
文字定数は単一の文字として記述するか、単一引用符の内側のエスケープ・シーケンス('a')として記述します。 文字定数には、charではなくint型が割り当てられます。文字定数は、ASCII文字セット内のその文字の値によって値が決定される整数定数と同等です。 文字とその値のリストは、ascii(7)のマニュアル・ページを参照してください。 次の表に示す特殊なエスケープ・シーケンスを使用することもできます。 Dでは、ANSI Cと同じエスケープ・シーケンスを使用します。
表4-6 文字エスケープ・シーケンス
| エスケープ・シーケンス | 表現 | エスケープ・シーケンス | 表現 |
|---|---|---|---|
|
|
アラート |
|
円記号 |
|
|
バックスペース |
|
疑問符 |
|
|
改ページ |
|
一重引用符 |
|
|
改行 |
|
二重引用符 |
|
|
キャリッジ・リターン |
|
8進数値0oo |
|
|
水平タブ |
|
16進数値0xhh |
|
|
垂直タブ |
|
NULL文字 |
複数の文字指定子を一重引用符内に含めて、対応する文字指定子に従って初期化された個々のバイトの整数を作成できます。 これらのバイトは、文字定数の左から右の順に読み取られ、オペレーティング環境のネイティブのエンディアンに対応する順序で結果の整数に割り当てられます。 1つの文字定数に、最大8個の文字指定子を含めることができます。
文字列定数は、二重引用符で囲むことにより、任意の長さで作成できます("hello")。 文字列定数には、リテラルの改行文字を含めることはできません。 改行が含まれる文字を作成するには、リテラルの改行文字を入力するかわりに、\nというエスケープ・シーケンスを使用します。 文字列定数には、前述の文字定数について示した特殊文字のエスケープ・シーケンスを含めることができます。 ANSI Cの場合と同様に、文字列は、NULL文字(\0)で終わる文字の配列として表されます。このNULL文字は、文字列定数を宣言するたびに暗黙的に追加されます。 文字列定数には、Dの特殊なstring型が割り当てられます。 Dコンパイラには、文字列として宣言された文字配列を比較およびトレースするための一連の特別な機能が用意されています。
算術演算子
次の表に、二項算術演算子を示します。 これらの演算子が整数に対して持つ意味はすべて、ANSI Cの場合と同じです。
表4-7 バイナリ算術演算子
| 演算子 | 説明 |
|---|---|
|
|
整数の加算 |
|
|
整数の減算 |
|
|
整数の乗算 |
|
|
整数の除算 |
|
|
整数のモジュラス |
Dの算術演算は、整数オペランドまたはポインタに対してのみ実行できます。 Dプログラムでは、浮動小数点オペランドに対する算術演算は実行できません。 DTraceの実行環境では、整数のオーバーフローまたはアンダーフローに対して一切処理されません。 オーバーフローやアンダーフローが発生する状況では、それらの条件をチェックする必要があります。
ただし、DTrace実行環境では、/および%演算子が不適切に使用されたことによって、エラーがないことで除算を自動的にチェックし、報告します。 コンパイル時に検出可能な無効な除算操作がDプログラムに含まれていると、コンパイル・エラーが返され、コンパイルは失敗します。 実行時に無効な除算操作が実行されると、現在の句の処理が終了し、ERRORプローブがアクティブ化されます。 DプログラムにERRORプローブの句がない場合、エラーが出力され、トレースが続行されます。 それ以外の場合は、ERRORプローブに割り当てられた句のアクションが処理されます。 DTraceによって検出されるエラーは、別のDTraceユーザーやOSカーネルには影響しません。 そのため、こうしたエラーのいずれかがDプログラムに誤って含まれている場合に発生する損害について懸念する必要はありません。
これらの二項演算子に加えて、+演算子と-演算子は単項演算子として使用することもできます。これらの演算子は、どの二項算術演算子よりも優先されます。 すべてのD演算子の優先順位と結合性プロパティの詳細は、「演算子の優先順位」を参照してください。 優先順位を制御するには、カッコ(())で式をグループ化します。
関係演算子
次の表に、二項関係演算子を示します。 これらの演算子が持つ意味はすべて、ANSI Cの場合と同じです。
表4-8 D関係演算子
| 演算子 | 説明 |
|---|---|
|
|
左のオペランドは右のオペランドより小さい |
|
|
左のオペランドは右のオペランド以下 |
|
|
左のオペランドは右のオペランドより大きい |
|
|
左のオペランドは右のオペランド以上 |
|
|
左のオペランドは右のオペランドと等しい |
|
|
左のオペランドは右のオペランドと等しくない |
関係演算子は、Dの述語の記述で最も頻繁に使用されます。 各演算子は、int型の値(条件がtrueの場合は1、falseの場合は0)に評価されます。
関係演算子は、整数、ポインタまたは文字列のペアに適用できます。 ポインタ同士を比較した場合、2つのポインタの整数を符号なし整数とみなして比較した場合と同じ結果になります。 文字列同士を比較した場合、結果は、2つのオペランドに対してstrcmp()を実行した場合と同じになります。 次の表に、Dの文字列比較とその結果の例を示します。
| Dの文字列比較 | 結果 |
|---|---|
|
|
1 ( |
|
|
1 ( |
|
|
0 ( |
関係演算子を使用して、列挙型に関連付けられているデータ・オブジェクトを、列挙で定義された列挙子タグと比較することもできます。
論理演算子
次の表に、二項論理演算子を示します。 最初の2つの演算子は、対応するANSI C演算子と同じものです。
表4-9 D論理演算子
| 演算子 | 説明 |
|---|---|
|
|
論理演算子 |
|
|
論理演算子 |
|
|
論理演算子 |
論理演算子は、Dの述語の記述で最も頻繁に使用されます。 論理演算子ANDは、左のオペランドがfalseの場合に右の式は評価しないという短絡評価を実施します。 論理演算子ORも、左のオペランドがtrueの場合に右の式は評価しないという短絡評価を実施します。 論理演算子XORは、短絡を実施しません。 どちらの式オペランドも常に評価されます。
バイナリ論理演算子に加えて、単項演算子!を使用して、単一オペランドの論理否定を実行できます。つまり、0オペランドを1に、0以外のオペランドを0に変換します。 慣例により、Dプログラムでは、Boolean値を表す整数を操作するときには!、Boolean以外の整数を操作するときには== 0を使用しますが、これらの式は同等です。
論理演算子は、整数型またはポインタ型のオペランドに適用できます。 論理演算子は、ポインタ・オペランドを符号なしの整数値とみなします。 Dのすべての論理演算子および関係演算子の場合と同じく、0以外の整数値を持つオペランドは真、整数値0を持つオペランドは偽です。
ビット演算子
Dには、整数オペランド内の個々のビットを操作するために、次の表に示す次のビット演算子が用意されています。 これらの演算子が持つ意味はすべて、ANSI Cの場合と同じです。
表4-10 Dビット単位演算子
| 演算子 | 説明 |
|---|---|
|
|
単一のオペランドのビットごとの否定を実行するために使用できる単項演算子: オペランドの各0ビットを1ビットに変換し、オペランドの各1ビットを0ビットに変換します |
|
|
ビット単位の |
|
|
ビット単位の |
|
|
ビット単位の |
|
|
右のオペランドに指定されたビット数だけ左のオペランドを左にシフトする |
|
|
右のオペランドに指定されたビット数だけ左のオペランドを右にシフトする |
シフト演算子を使用すると、特定の整数オペランド内のビットを左右に移動できます。 左へシフトすると、結果の右側にある空のビット位置にゼロが入力されます。 符号なし整数オペランドを使用して右へシフトすると、結果の左側の空のビット位置にゼロが入力されます。 符号付き整数オペランドを使用して右へシフトすると、左側の空のビット位置に符号ビットの値が入力されます。この操作は、算術シフト演算とも呼ばれます。
ビット数が負の値である場合や、左側のオペランド自体のビット数より大きい場合、整数値をシフトすると、未定義の結果が得られます。 この条件がDプログラムのコンパイル時に検出されると、Dコンパイラによりエラー・メッセージが生成されます。
代入演算子
次の表に、二項代入演算子を示します。 変更できるのは、Dの変数と配列のみです。 カーネル・データ・オブジェクトと定数は、Dの代入演算子を使用して変更することはできません。 代入演算子が持つ意味は、ANSI Cの場合と同じです。
表4-11 D割当演算子
| 演算子 | 説明 |
|---|---|
|
|
左のオペランドを右の式の値と等しくする |
|
|
左のオペランドを右の式の値の分だけ増分する |
|
|
左のオペランドを右の式の値の分だけ減分する |
|
|
左のオペランドに右の式の値を掛ける |
|
|
左のオペランドを右の式の値で割る |
|
|
左のオペランドを右の式の値で割ったときの剰余を求める |
|
|
左のオペランドと右の式の値のORをビット単位で計算する |
|
|
左のオペランドと右の式の値のANDをビット単位で計算する |
|
|
左のオペランドと右の式の値のXORをビット単位で計算する |
|
|
右の式の値に指定されたビット数だけ左のオペランドを左にシフトする |
|
|
右の式の値に指定されたビット数だけ左のオペランドを右にシフトする |
代入演算子=の他に、前述の他の演算子のいずれかを使用して=演算子を使用する場合、他の代入演算子が省略されます。 たとえば、式x = x + 1は、式x += 1と同じです。 これらの代入演算子は、前述のバイナリ・フォームと同じオペランド型のルールに従います。
代入演算子の結果は、左側の式の新しい値と同等の式になります。 代入演算子やこれまで説明した任意の演算子を使用して、任意の複雑さの式を構成できます。 丸カッコ()を使用すると、複合式の項をグループ化できます。
インクリメント演算子およびデクリメント演算子
++および--が用意されています。 これらの演算子が持つ意味は、ANSI Cの場合と同じです。 これらの演算子は、変数に適用することも、構造体、共用体または配列の個々の要素に適用することもできます。 各演算子は、変数名の前または後に適用できます。 演算子が変数名の前にある場合は、まず変数が変更され、結果の式は新しい変数の値と等しくなります。 たとえば、次の2つのコード部分の結果は同じです。
x += 1; y = x;
y = ++x;y = x; x -= 1;
y = x--;
インクリメント演算子とデクリメント演算子を使用すると、変数を宣言せずに新しい変数を作成できます。 変数宣言を省略して、変数にインクリメント演算子またはデクリメント演算子を適用すると、この変数の型は暗黙的にint64_tとして宣言されます。
インクリメント演算子とデクリメント演算子を配列または構造体の要素に使用する場合は、要素への完全な参照の後または前に演算子を配置します。
int foo[5];
struct { int a; } bar;
bar.a++;
foo[1]++;
--foo[1];
インクリメント演算子とデクリメント演算子は、整数変数またはポインタ変数に適用できます。 これらの演算子を整数変数に適用すると、それに対応する値は1ずつ増分または減分されます。 これらの演算子をポインタ変数に適用すると、ポインタが参照しているデータ型のサイズ単位でポインタ・アドレスが増分または減分されます。
条件式
Dには、if-then-else構造を使用する機能がありません。 かわりに、3項演算子(?:)を使用した条件式が、この機能の一部を模倣するために使用できます。 3項演算子は、3つの式を関連付けます。最初の式を使用することで、残りの2つの式のいずれかを条件付きで評価します。
たとえば、次のD文を使用すると、iの値に応じて、変数xを2つの文字列のいずれかに設定できます:
x = i == 0 ? "zero" : "non-zero";
前述の例では、最初に式i == 0が評価され、それがtrueであるかfalseであるかが判断されます。 この式が真である場合、2番目の式が評価され、その値が返されます。 この式が偽である場合、3番目の式が評価され、その値が返されます。
その他のD演算子と同様に、単一の式で複数の?:演算子を使用することで、より複雑な式を作成できます。 たとえば、次の式は、0-9、a-fまたはA-Fのいずれかの文字を含むchar変数cを取り、この文字が16進(基本16)の整数の数字と解釈される場合にその値を戻します:
hexval = (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c + 10 - 'a' : c + 10 - 'A';
真の値と評価されるために、?:が使用されている最初の式は、ポインタまたは整数であることが必要です。 2番目と3番目の式には、互換性のある型を使用できます。 一方が文字列を返し、もう一方が整数を返すような条件式は構成できません。 2番目と3番目の式は、値を持つtrue式であることが必要です。 そのため、こうした式では値を返さないデータ・レポート関数は使用できません。 条件付きでデータをトレースする場合は、かわりに述語を使用します。
型変換
異なるが互換性のある型のオペランドを使用して式を作成する場合、型変換を実行して結果の式の型を特定します。 Dの型変換のルールは、ANSI Cの整数の算術変換ルールと同じです。 多くの場合、これらのルールは通常の算術変換と呼ばれます。
各整数型は、char、short、int、long、long longの順序でランク付けされます。それに対応する符号なし型には、その型の符号付きよりも高いランクが割り当てられますが、その次の整数型よりも低いランクが割り当てられます。 2つの整数オペランドを使用してx + yのような式を構成するときに、これらのオペランドの型が異なる場合、ランクが高い方のオペランド型が結果の型として使用されます。
変換が必要な場合は、ランクが低い方のオペランドが最初に、ランクの高い方の型に昇格されます。 昇格によってオペランドの値が変更されることはありません。符号に従ってより大きいコンテナに値が拡張されるのみです。 符号なしオペランドが昇格される場合、結果として生じる整数の未使用の上位ビットにゼロが入力されます。 符号付きオペランドが昇格される場合、符号の拡張を実行することによって未使用の上位ビットが入力されます。 符号付き型を符号なし型に変換すると、符号付き型は最初に符号拡張されてから、変換によって決定された新しい符号なし型が割り当てられます。
整数などの型は、別の型に明示的にキャストすることもできます。 ポインタと整数は、任意の整数型またはポインタ型にキャストできます。ただし、別の型にはキャストできません。
整数またはポインタによるキャストは、次のような式を使用して形成されます:
y = (int)x;
この例では、丸括弧で囲んだ変換先の型を元の式の接頭辞として使用しています。 整数をよりランクの高い型にキャストするには、昇格を実行します。 整数をよりランクの低い型にキャストするには、不要な整数の上位ビットをゼロにします。
Dでは、浮動小数点の算術演算が含まれていません。そのため、浮動小数点オペランドの変換やキャストは許可されていません。また、暗黙的な浮動小数点変換のルールも定義されていません。
演算子の優先順位
Dには、演算子の優先順位と結合性の複雑なルールが含まれています。 このルールは、ANSI Cの演算子の優先順位ルールとの正確な互換性を提供します。 次の表の次の項目は、上から優先順位の高い順に並べてあります。
表4-12 D演算子の優先順位と連想性
| 演算子 | 結合性 |
|---|---|
|
|
左から右 |
|
|
右から左 (これらは単項演算子である点に注意してください) |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
左から右 |
|
|
右から左 |
|
|
右から左 |
|
|
左から右 |
この表にリストされているカンマ(,)演算子は、ANSI Cのカンマ演算子との互換性用です。 式セットを左から右の順に評価し、最も右の式の値を返すために使用できます。 この演算子はCとの互換性のために用意されているもので、使用しないことをお薦めします。
演算子の優先順位の表に示されている()エントリは、関数コールを表します。 Dでは、カンマを使用して、関数の引数を列挙したり、連想配列キーのリストを作成することもできます。 このカンマはカンマ演算子とは別のもので、左から右の順で評価される保証はありません。 Dコンパイラでは、関数または連想配列へのキーの引数の評価順序は保証されません。 このようなコンテキストでは、式iとi++のペアなど、相互の副作用がある式の使用に注意してください。
演算子の優先順位の表に示されている[]エントリは、配列参照または連想配列参照を表します。 集積体は連想配列としても処理されることに注意してください。 []演算子は、固定サイズのC配列に索引を付けるために使用することもできます。
次の表では、D言語で提供されるその他の演算子の機能について詳しく説明します。
| 演算子 | 説明 |
|---|---|
|
|
オブジェクトのサイズを計算します。 |
|
|
タイプ・メンバーのオフセットを計算します。 |
|
|
オペランドを文字列に変換します。 |
|
|
データ型を変換します。 |
|
単項の |
オブジェクトのアドレスを計算します。 |
|
単項の |
オブジェクトへのポインタを間接参照します。 |
|
|
構造体またはユニオン型のメンバーにアクセスします。 |
型と定数の定義
この項では、Dで型の別名と名前付き定数を宣言する方法について説明します。 また、Dの型とプログラムおよびOSの型と識別子の名前空間の管理についても説明します。
typedef
typedefは、既存の型の別名として識別子を宣言するために使用します。 typedef宣言は、次の形式でプローブ節の外側で使用します:
typedef existing-type new-type ;
existing-typeは任意の型の宣言であり、new-typeはこの型の別名として使用する識別子です。 たとえば、Dコンパイラで次の宣言を内部使用し、uint8_t型の別名を作成します。
typedef unsigned char uint8_t;
型の別名は、標準の型が使用可能な任意の場所で使用できます。たとえば、変数、連想配列値、またはタプルのメンバーの型として使用できます。 また、次の例に示すように、typedefと、新しいstructの定義など、より複雑な宣言を組み合せることもできます:
typedef struct foo {
int x;
int y;
} foo_t;
前述の例では、struct fooは別名foo_tと同じ型を使用して定義されます。 Linux Cのシステム・ヘッダーでは通常、接尾辞_tを使用してtypedefの別名を示します。
列挙
プログラム内の定数のシンボル名を定義すると、プログラムが読みやすく、将来的に管理しやすくなります。 その方法の1つとして、列挙を定義します。これにより、一連の整数と、列挙子と呼ばれる一連の識別子を関連付けます。この列挙子が認識され、対応する整数値に置き換えられます。 列挙を定義するには、次のような宣言を使用します:
enum colors {
RED,
GREEN,
BLUE
};
この列挙の最初の列挙子REDには値ゼロが割り当てられ、後続の列挙子にはそれぞれ次の整数値が割り当てられます。
次の例に示すように、任意の列挙子に明示的な整数値を指定することもできます。これを行うには、列挙子に等号と整数定数を付けます:
enum colors {
RED = 7,
GREEN = 9,
BLUE
};
列挙子BLUEには値10が割り当てられます。これは、値が指定されず、以前の列挙子が9に設定されているためです。 列挙を定義すると、整数定数を使用するDプログラム内の任意の場所で列挙子を使用できます。 さらに、列挙enum colorsは、intと同等の型としても定義されます。 Dコンパイラは、intを使用できる場所であればどこでもenum型の変数の使用を許可します。また、enum型の変数には任意の整数値を代入できます。 型名が不要な場合は、宣言内でenum名を省略することもできます。
列挙子はプログラム内で後続するすべての節と宣言で参照可能です。 そのため、複数の列挙で同じ列挙子識別子を定義することはできません。 ただし、同じ列挙または異なる列挙内で同じ値を持つ複数の列挙を定義できます。 また、対応する列挙子のない整数を列挙型の変数に割り当てることもできます。
Dの列挙の構文は、対応するANSI Cの構文と同じです。 Dでも、OSカーネルとそのロード可能なモジュールで定義された列挙にアクセスできます。 こうした列挙子は、Dプログラムではグローバルに参照可能でないことに注意してください。 カーネル列挙子が表示されるのは、対応する列挙型のオブジェクトとの比較を行う際に引数として指定する場合のみです。 この機能により、OSカーネルで定義されている膨大な列挙のコレクションとの識別子名の不用意な衝突からDプログラムを保護します。
インライン
Dという名前の定数は、inlineディレクティブを使用して定義することもできます。これにより、コンパイル時に事前定義された値または式に置換される識別子を作成するための一般的な手段、またはシステム・ヘッダー・ファイルのコピーを含めることができます。 インライン・ディレクティブは、Cプリプロセッサで提供される#defineディレクティブよりも強力な語彙置換形式です。これは、置換には実際の型が割り当てられ、一連の語彙トークンではなくコンパイルされた構文ツリーを使用して置換を実行できるためです。 inlineディレクティブは、次の形式の宣言を使用して指定します:
inline type name = expression;
typeは既存の型の型宣言です。nameはインラインまたはグローバル変数としてまだ定義されていない任意の有効なD識別子です。expressionは任意の有効なD式です。 インライン・ディレクティブの処理後、プログラム・ソース内のnameの後続の各インスタンスが、コンパイルされた形式expressionで置き換えられます。
たとえば、次のDプログラムでは、文字列"hello"と整数値123がトレースされます。
inline string hello = "hello";
inline int number = 100 + 23;
BEGIN
{
trace(hello);
trace(number);
}
インライン名は、対応するタイプのグローバル変数が使用されているすべての場所で使用できます。 コンパイル時に、インライン式が整数定数または文字列定数に評価された場合、スカラー配列次元など、定数式を必要とする状況でもインライン名を使用することもできます。
インライン式は、ディレクティブの評価の一環として構文エラーについてチェックされます。 式の結果の型は、D代入演算子(=)に使用されるルールに従って、inlineで定義される型と互換性を持つ型になることが必要です。 インライン式ではinline識別子自体を参照できません。再帰的定義は許可されていません。
DTraceソフトウェア・パッケージは、システム・ディレクトリ/usr/lib64/dtrace/installed-versionに複数のDソース・ファイルをインストールします。このファイルには、Dプログラムで使用できるインライン・ディレクティブが含まれています。
たとえば、signal.dライブラリには次の形式のディレクティブが含まれます:
inline int SIGHUP = 1;
inline int SIGINT = 2;
inline int SIGQUIT = 3;
...
これらのインライン定義により、sigaction(2)マニュアル・ページで説明されているように、Oracle Linuxシグナル名の現行セットにアクセスできます。 同様に、errno.dライブラリには、errno(3)マニュアル・ページで説明されているC errno定数のインライン・ディレクティブが含まれます。
デフォルトでは、Dコンパイラは、すべてのDプログラムでこれらの定義を使用できるように、提供されているすべてのDライブラリ・ファイルを自動的に含めます。
型の名前空間
ANSI Cなどの従来の言語では、型の可視性は、型が関数や別の宣言の内側でネストされているかどうかによって決まります。 Cプログラムの外部スコープで宣言された型には、単一のグローバル名前空間が関連付けられるため、これらの型は、プログラム全体にわたって表示されます。 通常、Cヘッダー・ファイルに定義されている型は、この外部スコープに含まれます。 こうした言語とは異なり、Dでは複数の外部スコープから型にアクセスできます。
Dは、OSカーネル、関連するロード可能なカーネル・モジュールのセット、システム上で実行されるユーザー・プロセスなど、ソフトウェア・スタックの異なるレイヤーにわたる動的な可観測性を提供する言語です。 単一のDプログラムにより、プローブをインスタンス化し、複数のカーネル・モジュールや、その他の独立したバイナリ・オブジェクトにコンパイルされたソフトウェア・エンティティからデータを収集できます。 そのため、DTraceやDコンパイラで使用可能な型の空間には、定義が異なっていることもある同じ名前の複数のデータ型が存在する可能性があります。 この状況を管理するために、Dコンパイラは各型を、それを含むプログラム・オブジェクトで識別されるネームスペースに関連付けます。 メイン・カーネルやカーネル・モジュールなど、特定のカーネル・レベル・オブジェクトの型にアクセスするには、任意の型名にオブジェクト名と逆引用符(`)のスコープ演算子を指定します。
fooという名前のカーネル・モジュールに次のC型宣言が含まれている場合:
typedef struct bar {
int x;
} bar_t;
タイプstruct barおよびbar_tは、次のタイプ名を使用してDからアクセスできます:
struct foo`bar
foo`bar_t
たとえば、カーネルにinclude/linux/sched.hで記述されたtask_structが含まれているとします。 この構造体の定義は、ビルド時のカーネル構成に応じて異なります。 この構造体に関する情報(サイズなど)は、次のように参照することで確認できます:
sizeof(struct vmlinux`task_struct)
逆引用符演算子は、D変数宣言の型を指定する場合やDプローブ節で式をキャストする場合など、型の名前が適切な場合には、任意のコンテキストで使用できます。
Dコンパイラには、名前CとDを使用する2つの特殊な組込み型の名前空間も用意されています。 C言語のネームスペースには、intなどの標準ANSI Cの固有の型が最初に移入されます。 また、dtrace -Cコマンドを実行することでCプリプロセッサ(cpp)を使用して得られた型定義がCスコープで処理されて追加されます。 そのため、コンパイル・エラーの発生なしに、別の型の名前空間ですでに参照可能な型宣言が含まれるCヘッダー・ファイルを組み込むことができます。
Dの型の名前空間には、最初に、intやstringなどのD固有の型と、uint64_tなどのDの組込み型の別名が移入されます。 Dプログラム・ソース内で使用される新しい型宣言はすべて、Dの型の名前空間に自動的に追加されます。 他のネームスペースのメンバー・タイプで構成されるDプログラムでstructなどの複合タイプを作成する場合、メンバー・タイプは宣言によってDネームスペースにコピーされます。
逆引用符の演算子を使用して明示的に名前空間が指定されていない型宣言を検出すると、Dコンパイラは指定された型名を使用して一致する型名を検出するために、アクティブな型の名前空間のセットを検索します。 常にCの名前空間が最初に検索され、その後でDの名前空間が検索されます。 CとDのどちらの名前空間でも型名が見つからない場合は、アクティブなカーネル・モジュールの型の名前空間がロード・アドレスの順に検索されます。ただし、ロード可能なモジュール間の順序付けプロパティは保証されません。 別のカーネル・モジュールとの型名の競合を避けるために、ロード可能なカーネル・モジュールで定義された型にアクセスする場合は、スコープ演算子を使用してください。
Dコンパイラは、OSのソース・コードに関連付けられた型にアクセスするために、コアLinuxカーネル・モジュールに付随する圧縮形式のANSI Cデバッグ情報を使用します。これにより、対応するCのインクルード・ファイルにアクセスする必要がなくなります。 このシンボリック・デバッグ情報は、システム上のすべてのカーネル・モジュールで使用可能なわけではありません。 DTraceで使用することを目的とした圧縮形式のCのデバッグ情報が含まれないモジュールの名前空間内の型にアクセスしようとすると、Dコンパイラはエラーを報告します。