Solaris 動的トレースガイド

第 2 章 型、演算子、および式

D では、さまざまなデータオブジェクトにアクセスし、操作できます。 具体的には、変数やデータ構造を作成または変更したり、オペレーティングシステムカーネルやユーザープロセスに定義されているデータオブジェクトにアクセスしたり、整数定数、浮動小数点定数、文字列定数を宣言したりすることができます。D は、オブジェクトの操作や複合式の作成に使用される ANSI-C 演算子の上位集合を提供します。この章では、型、演算子、および式の規則の詳細を説明します。

識別子名とキーワード

D 識別子名は、アルファベットの大文字と小文字 、数字、および下線で構成されます。先頭文字は必ずアルファベットまたは下線になります。先頭文字が下線 (_) の識別子名はすべて、D システムライブラリ用に予約されています。これらの名前を D プログラム内で使用してはなりません。D プログラムでは、通常、変数名はアルファベットの大文字と小文字、定数名はすべて大文字で記述されます。

D 言語のキーワードは、プログラミング言語構文そのもので使用するために予約されている特別な識別子です。これらの名前は常にアルファベットの小文字のみで指定され、D 変数名に使用することは禁じられています。

表 2–1 D のキーワード

auto*

goto*

sizeof

break*

if*

static*

case*

import*+

string+

char

inline

stringof+

const

int

struct

continue*

long

switch*

counter*+

offsetof+

this+

default*

probe*+

translator+

do*

provider*+

typedef

double

register*

union

else*

restrict*

unsigned

enum

return*

void

extern

self+

volatile

float

short

while*

for*

signed

xlate+

D では、ANSI-C キーワードの上位集合がキーワードとして予約されています。将来 D 言語で使用するために予約されているキーワードには、アスタリスク (*) が付けられています。将来のために予約されているキーワードを使用しようとすると、D コンパイラから構文エラーが返されます。D では定義されているが ANSI-C では定義されていないキーワードには、プラス記号 (+) が付けられています。D では、ANSI-C のすべての型および演算子を使用できます。D プログラミングの主要な特徴は、制御フロー構文を使用しない点です。ANSI-C で制御フローに関連付けられたキーワードは、D では将来のために予約されています。

データ型とサイズ

D は、整数と浮動小数点定数の基本データ型を提供しています。算術演算は、D プログラム内の整数に対してのみ実行可能です。D では、データ構造を初期化するために浮動小数点定数を使用できますが、浮動小数点算術演算の使用は許可されていません。D は、プログラムの記述用として、32 ビットと 64 ビットのデータモデルを提供しています。プログラムの実行時には、稼働中のオペレーティングシステムカーネルに関連付けられたネイティブデータモデルが使用されます。システムのネイティブデータモデルは、isainfo -b コマンドで確認できます。

以下の表に、2 つのデータモデルの整数型名とサイズを一覧します。整数は常に、システムのネイティブバイトエンコーディングの順番で、2 の補数として表現されます。

表 2–2 D の整数データ型

型名 

サイズ (32 ビット) 

サイズ (64 ビット) 

char

1 バイト 

1 バイト 

short

2 バイト 

2 バイト 

int

4 バイト 

4 バイト 

long

4 バイト 

8 バイト 

long long

8 バイト 

8 バイト 

整数型の前には、修飾子 signed または unsigned が付けられます。符号修飾子が存在しない場合、その型は符号付き (signed) であると見なされます。D コンパイラでは、以下のような型の別名も使用できます。

表 2–3 D 整数型の別名

型名 

説明 

int8_t

1 バイトの符号付き整数 

int16_t

2 バイトの符号付き整数 

int32_t

4 バイトの符号付き整数 

int64_t

8 バイトの符号付き整数 

intptr_t

ポインタと同じサイズの符号付き整数 

uint8_t

1 バイトの符号なし整数 

uint16_t

2 バイトの符号なし整数 

uint32_t

4 バイトの符号なし整数 

uint64_t

8 バイトの符号なし整数 

uintptr_t

ポインタと同じサイズの符号なし整数 

これらの別名は、1 つ前の表に示した基本型と対応しており、データモデルごとに定義されています。たとえば、型名 uint8_t は、unsigned char 型の別名です。D プログラム内で使用する型の別名を独自に定義する方法については、第 8 章型と定数の定義を参照してください。

D の浮動小数点型は、ANSI-C の宣言と型に互換性があります。D では、浮動小数点演算子はサポートされていませんが、printf() 関数を使って、浮動小数点型データオブジェクトのトレースおよび書式設定を行うことができます。使用可能な浮動小数点型は、次の表のとおりです。

表 2–4 D の浮動小数点データ型

型名 

サイズ (32 ビット) 

サイズ (64 ビット) 

float

4 バイト 

4 バイト 

double

8 バイト 

8 バイト 

long double

16 バイト 

16 バイト 

D では、ASCII 文字列を表す特殊な string 型も使用できます。文字列については、第 6 章文字列で詳しく説明します。

定数

整数定数は、10 進法 (12345)、8 進法 (012345)、16 進法 (0x12345) で記述できます。8 進法 (base 8) の定数には、接頭辞としてゼロを付ける必要があります。16 進法 (base 16) の定数には、接頭辞として 0x または 0X を付ける必要があります。整数定数には、その値を表す型として、intlonglong long のうちもっとも小さい型が割り当てられます。負の値には、符号付きの型が割り当てられます。正の値で、符号付きの型で表すには値が大きすぎる場合は、符号なしの型が割り当てられます。D の型であることを明示的に指定するには、次のいずれかの接尾辞を割り当てます (すべての整数定数に共通)。

u または U

コンパイラによって選択された unsigned

l または L

long

ul または UL

unsigned long

ll または LL

long long

ull または ULL

unsigned long long

浮動小数点定数は常に 10 進数で記述します。さらに、小数点 (12.345) か指数 (123e45)、またはその両方 (123.34e-5) を含める必要があります。浮動小数点定数には、デフォルトで double 型が割り当てられます。D の型であることを明示的に指定するには、次のいずれかの接尾辞を割り当てます (すべての浮動小数点定数に共通)。

f または F

float

l または L

long double

文字定数は単一の文字か、エスケープシーケンスを単一引用符で囲んだ形式 ('a') で記述します。文字定数には、int 型が割り当てられます。文字定数は、ASCII 文字集合内のその文字の値に対応する値を持つ整数定数と同等です。文字とその値の対応関係は、ascii(5) のマニュアルページで確認できます。文字定数には、以下の表に示す特殊なエスケープシーケンスを含めることもできます。D では、ANSI-C と同じエスケープシーケンスがサポートされています。

表 2–5 D の文字エスケープシーケンス

\a

警告 

\\

バックスラッシュ 

\b

バックスペース 

\?

疑問符 

\f

用紙送り 

\'

単一引用符 

\n

改行 

\”

二重引用符 

\r

キャリッジリターン 

\0oo

8 進数値 0oo

\t

水平タブ 

\xhh

16 進数値 0xhh

\v

垂直タブ 

\0

NULL 文字 

複数の文字指定子を 1 組の単一引用符で囲むことにより、整数のバイトを、対応する文字指定子に合わせて個別に初期化できます。これらのバイトは、文字定数の左から順に読み取られ、使用しているオペレーティング環境のネイティブの並び順 (エンディアン) で、整数に割り当てられます。1 つの文字定数に、最大 8 個の文字指定子を含めることができます。

文字列定数は、その長さを問わず、二重引用符で囲んだ形式 ("hello") で表されます。文字列定数には、改行文字をそのまま含めることはできません。改行文字を含めたい場合は、実際に改行文字を入力する代わりに、\n というエスケープシーケンスを入力します。文字列定数には、文字定数で使用できる特殊文字エスケープシーケンス (上記参照) を含めることができます。ANSI-C の場合と同じく、文字列は、NULL 文字 (\0) で終わる文字配列で表されます。この NULL 文字は、宣言された文字列定数ごとに暗黙的に挿入されるものです。文字列定数には、D の特殊な string 型が割り当てられます。D コンパイラは、文字列として宣言された文字配列の比較とトレースを行う特別な機能セットを提供しています。この機能セットについては、第 6 章文字列を参照してください。

算術演算子

D プログラムでは、次の表に示す二項算術演算子を使用できます。これらの演算子で整数を操作したときの効果は、ANSI-C の場合と同じです。

表 2–6 D の二項算術演算子

+

整数の加算 

-

整数の減算 

*

整数の乗算 

/

整数の除算 

%

整数の剰余演算 

D の算術演算は、整数オペランドかポインタに対してのみ実行できます (第 5 章ポインタと配列を参照)。D プログラムの浮動小数点オペランドに対して、算術演算を実行することはできません。DTrace 実行環境は、整数のオーバーフローまたはアンダーフローに対して、何の処理も行いません。整数のオーバーフロー、アンダーフローについては、状況に応じてユーザー自身が確認する必要があります。

DTrace 実行環境では、/ 演算子や % 演算子の誤用によるゼロ除算エラーが自動的に検査され、報告されます。D プログラムで無効な除算が実行されると、その影響を受ける計測機能が自動的に無効化され、エラーが報告されます。DTrace でエラーが検出されても、その他の DTrace ユーザーやオペレーティングシステムカーネルに悪影響が及ぶことはありません。したがって、エラーのある D プログラムを不注意で作成してしまったとしても、障害の起きる心配はありません。

上記の二項演算子のほかに、+ - を単項演算子として使用することもできます。この 2 つの演算子は、どの二項算術演算子よりも優先されます。D の演算子の優先順位と結合規則については、表 2–11 を参照してください。優先順位を制御したい場合は、式を丸括弧 ( ) で囲んでグループ化します。

関係演算子

D プログラムでは、次の表に示す二項関係演算子を使用できます。これらの演算子の効果は、ANSI-C の場合と同じです。

表 2–7 D の関係演算子

<

左のオペランドは右のオペランドより小さい 

<=

左のオペランドは右のオペランド以下 

>

左のオペランドは右のオペランドより大きい 

>=

左のオペランドは右のオペランド以上 

==

左のオペランドは右のオペランドと等しい 

!=

左のオペランドは右のオペランドと等しくない 

関係演算子は、D の述語の記述によく使用されます。各演算子は、int 型の値 (条件が真の場合は 1、偽の場合は 0) を返します。

関係演算子は、整数同士、ポインタ同士、または文字列同士の組に適用されます。ポインタ同士を比較した場合、双方を符号なし整数と見なして整数比較を実行した場合と同じ結果になります。文字列同士を比較した場合、双方のオペランドに対して strcmp(3C) を実行した場合と同じ結果になります。以下に、D の文字列比較とその結果の例を示します。

"coffee" < "espresso"

... 1 (真) を返す 

"coffee" == "coffee"

... 1 (真) を返す 

"coffee" >= "mocha"

... 0 (偽) を返す 

関係演算子は、列挙型のデータオブジェクトと、列挙によって定義された列挙子タグとの比較にも使用されます。列挙は、名前付きの整数定数を作成するときに使用します。詳細は、第 8 章型と定数の定義を参照してください。

論理演算子

D プログラムでは、次の二項論理演算子を使用できます。最初の 2 つの演算子は、対応する ANSI-C 演算子と同じ機能を持っています。

表 2–8 D の論理演算子

&&

論理積「AND」: 両方のオペランドが真の場合、真

||

論理和「OR」: いずれか一方のオペランド、または両方のオペランドが真の場合、真

^^

排他的論理和「XOR」: いずれか一方のオペランドだけが真の場合、真

論理演算子は、D の述語の記述によく使用されます。論理積 AND 演算子は、短絡評価を行います。 左側のオペランドが偽の場合、右側の式は評価されません。論理和 OR 演算子も短絡評価を行います。 左側のオペランドが真の場合、右側の式は評価されません。排他的論理和 XOR 演算子は、短絡評価を行いません。 必ず両方の式のオペランドが評価されます。

二項論理演算子のほかに、単項演算子 ! も使用できます。この単項演算子は、単一のオペランドの論理否定を実行します。 つまり、0 オペランドを 1 に、0 以外のオペランドを 0 に変換します。!== 0 は機能上同等ですが、D プログラムでは、慣例上、ブール値を表す整数を操作するときは !、ブール型以外の整数を操作するときは == 0 を使用します。

論理演算子は、整数型またはポインタ型のオペランドに適用されます。論理演算子は、ポインタオペランドを符号なしの整数値と見なします。D のすべての論理演算子、関係演算子の場合と同じく、0 以外の整数値を持つオペランドは真、整数値 0 を持つオペランドは偽になります。

ビット演算子

D では、次の二項演算子を使って、整数オペランドに含まれる個々のビットを操作できます。これらの演算子の効果は、ANSI-C の場合と同じです。

表 2–9 D のビット演算子

&

ビット単位の論理積 AND 

|

ビット単位の論理和 OR 

^

ビット単位の排他的論理和 XOR 

<<

左のオペランドを、右のオペランドに指定されたビット数だけ左にシフトする 

>>

左のオペランドを、右のオペランドに指定されたビット数だけ右にシフトする 

二項演算子 & では、整数オペランドのビットを消去できます。二項演算子 | では、整数オペランドにビットを設定できます。二項演算子 ^ は、対応するオペランドビットが 1 つだけ設定されたビット位置に 1 を返します。

シフト演算子では、指定された整数オペランド内のビットを左右に移動できます。左シフトでは、結果の右側の空のビット位置にゼロが格納されます。符号なし整数オペランドを使った右シフトでは、結果の左側の空のビット位置にゼロが格納されます。符号付き整数オペランドを使った右シフトでは、左側の空のビット位置に符号ビットの値が格納されます。この操作を「算術シフト演算」と呼びます。

ビット数が負の値である場合や、左側のオペランドのビット数より大きい場合、整数値シフトの結果は未定義です。D プログラムのコンパイル時にこの条件が検出されると、D コンパイラからエラーメッセージが表示されます。

二項論理演算子のほかに、単項演算子 ~ も使用できます。この単項演算子は、単一のオペランドのビット単位の否定を実行します。 つまり、オペランド内の 0 ビットは 1 ビット、1 ビットは 0 ビットに変換されます。

代入演算子

D では、次の二項代入演算子を使って、D 変数を変更できます。変更できるのは、D の変数と配列だけです。D の代入演算子では、カーネルデータオブジェクトや定数は変更できません。代入演算子の効果は、ANSI-C の場合と同じです。

表 2–10 D の代入演算子

=

左のオペランドを右の式の値と等しくする 

+=

左のオペランドを右の式の値の分だけ増分する 

-=

左のオペランドを右の式の値の分だけ減分する 

*=

左のオペランドに右の式の値を掛ける 

/=

左のオペランドを右の式の値で割る 

%=

左のオペランドを右の式の値で割ったときの剰余を求める 

|=

左のオペランドと右の式の値の論理和 OR をビット単位で計算する 

&=

左のオペランドと右の式の値の論理積 AND をビット単位で計算する 

^=

左のオペランドと右の式の値の排他的論理和 XOR をビット単位で計算する 

<<=

左のオペランドを、右の式の値で指定されたビット数だけ左にシフトする 

>>=

左のオペランドを、右の式の値で指定されたビット数だけ右にシフトする 

= 以外の代入演算子は、= とすでに説明したその他の演算子を組み合わせた演算の省略形として使用できます。たとえば、x = x + 1 という式は、x の数値が 1 度評価される点を除いて、x += 1 と同じです。これらの代入演算子は、以前に説明した二項のオペランドと同じ規則で使用します。

代入演算子の結果は、左側の式の新しい値と同等の式になります。代入演算子やこれまでに説明したその他の演算子を組み合わせると、複合式を表現できます。複合式の項は、丸括弧 ( ) を使ってグループ化できます。

インクリメント演算子とデクリメント演算子

D では、特殊な単項演算子 ++-- を使って、ポインタや整数の増分と減分を行うことができます。これらの演算子の効果は、ANSI-C の場合と同じです。これらの演算子は変数にのみ適用可能で、変数名の直前または直後に付加します。変数名の直前に演算子を付けた場合、まず変数が変更され、結果の式は変更後の変数の値と等しくなります。たとえば、次の 2 つの式の結果は同じです。

x += 1;

y = ++x;

y = x;

 

変数名の直後に演算子を付けた場合、式で使用する現在の値が返されたあと、変数が変更されます。たとえば、次の 2 つの式の結果は同じです。

y = x;

y = x--;

x -= 1;

 

インクリメント演算子とデクリメント演算子を使用すると、変数宣言なしで新しい変数を作成できます。変数宣言を省略して、変数にインクリメント演算子かデクリメント演算子を適用した場合、この変数の型は暗黙的に int64_t になります。

インクリメント演算子とデクリメント演算子は、整数変数またはポインタ変数に適用できます。これらの演算子を整数変数に適用した場合、対応する値が 1 増分または 1 減分されます。これらの演算子をポインタ変数に適用した場合、ポインタアドレスが、ポインタが参照しているデータ型のサイズの分だけ増分または減分されます。D のポインタとポインタ算術演算については、第 5 章ポインタと配列を参照してください。

条件式

D では if-then-else 構文はサポートされていませんが、演算子 ?: を使った単純な条件式がサポートされています。これらの演算子では、3 つの式を関連付けることができます。具体的には、最初の式が、残りの 2 つの式のうちどちらを評価するかを決める、条件式になります。たとえば、次の D 文では、値 i に応じて、2 つの文字列のうちのどちらかが、変数 x の設定に使用されます

x = i == 0 ? "zero" : "non-zero";

この例では、最初に式 i == 0 が評価され、真であるか偽であるかが求められます。最初の式が真の場合、2 番目の式が評価され、?: 式の値が返されます。最初の式が偽の場合、3 番目の式が評価され、?: 式の値が返されます。

ほかの D 演算子の場合と同様に、複数の ?: 演算子を 1 つの式で使用することで、より複雑な式を作成できます。たとえば、次の式は、0 - 9、a - z、A - Z のいずれかの文字を含む char 変数 c を取り、この文字を数字と見なした場合の値を 16 進 (base 16) の整数として返します。

hexval = (c >= '0' && c <= '9') ? c - '0' :
    (c >= 'a' && c <= 'z') ? c + 10 - 'a' : c + 10 - 'A';

?: が使用されている最初の式の値が真と評価されるためには、ポインタまたは整数である必要があります。2 番目と 3 番目の式は、互換性のある型であれば何でもかまいません。ただし、一方が文字列型、もう一方が整数型を返すような条件式は作成できません。また、2 番目と 3 番目の式では、trace()printf() などのトレース関数は呼び出せません。条件付きでデータをトレースしたい場合は、第 1 章はじめにで説明したように、述語を使用してください。

型変換

式に含まれる複数のオペランドの型が違っていても、相互に互換性のある型であれば、型変換が実行されて、結果の式の型が決まります。D の型変換の規則は、ANSI-C の整数の算術変換規則と同じです。この規則を、「通常の算術変換」と呼びます。

変換規則について簡単に説明します。 整数型はそれぞれ char、short、int、long、long long の順に順位付けられます。符号なし型は、対応する符号付き型より上位 (ただし 1 つ上位の整数型より下位) に順位付けられます。2 つの整数オペランドを使って x + y のような式を作成したとしましょう。この 2 つのオペランドの型が異なる場合、順位が高いほうの型が、式の結果の型になります。

変換が必要な状況では、順位が低いほうの型が、順位の高いほうの型に「拡張」されます。型が拡張されても、オペランドの値が変更されるわけではありません。 値は、その符号に従って、より大きいコンテナに拡張されるだけです。符号なしオペランドの拡張では、結果の整数の未使用の上位ビットにゼロが格納されます。符号付きオペランドの拡張では、未使用の上位ビットに符号拡張の実行結果が格納されます。符号付きの型を符号なしの型に変換した場合、最初に符号付きの型が拡張され、その後、変換によって求められた、新しい符号なしの型が割り当てられます。

整数などの型は、明示的に別の型に「キャスト」することもできます。D のポインタと整数は、任意の整数型またはポインタ型にキャストできます。ただし、これ以外の型にキャストすることはできません。文字列や文字配列のキャストと拡張の規則については、第 6 章文字列で説明します。整数またはポインタをキャストするときは、次のような式を使用します。

y = (int)x;

丸括弧の中に最終的な型を指定し、元となる式の前に付加します。整数をより上位の型にキャストするときは、拡張が行われます。整数をより下位の型にキャストするときは、不要な上位ビットにゼロが格納されます。

D では、浮動小数点算術演算は実行できません。そのため、浮動小数点オペランドの変換やキャストは許可されておらず、また、暗黙的な浮動小数点変換の規則も定義されていません。

優先度

以下の表に、D の演算子の優先順位と結合の規則を一覧します。これらの規則は少し複雑ですが、ANSI-C の演算子の優先順位の規則との完全な互換性を実現するためには欠かせないものです。表の項目は、上から優先順位の高い順になっています。

表 2–11 D の演算子の優先順位と結合規則

演算子 

結合規則 

() [] -> .

左から右 

! ~ ++ -- + - * & (type) sizeof stringof offsetof xlate

右から左 

* / %

左から右 

+ -

左から右 

<< >>

左から右 

< <= > >=

左から右 

== !=

左から右 

&

左から右 

^

左から右 

|

左から右 

&&

左から右 

^^

左から右 

||

左から右 

?:

右から左 

= += -= *= /= %= &= ^= |= <<= >>=

右から左 

,

左から右 

この表の中には、まだ説明していない演算子も含まれています。これらの演算子については、次の章以降で説明します。

sizeof

オブジェクトのサイズを計算する (第 7 章構造体と共用体)

offsetof

型メンバーのオフセットを計算する (第 7 章構造体と共用体)

stringof

オペランドを文字列に変換する (第 6 章文字列)

xlate

データ型を翻訳する (第 40 章トランスレータ)

単項の &

オブジェクトのアドレスを計算する (第 5 章ポインタと配列)

単項の *

オブジェクトへのポインタを間接参照する (第 5 章ポインタと配列)

->.

構造体型または共用体型のメンバーにアクセスする (第 7 章構造体と共用体)

表中のコンマ (,) 演算子は、ANSI-C のコンマ演算子との互換性を実現するために用意されたものです。この演算子は、複数の式を左から順に評価し、一番右の式の値を返します。この演算子は C との完全な互換性を実現するためのものであり、通常は使用しません。

演算子の優先順位の表にある () は、関数呼び出しを表します。printf()trace() などの関数呼び出しの例は、第 1 章はじめにに記載されています。D では、コンマを使って、関数の引数を列挙したり、連想配列のキーのリストを作成したりできます。このコンマはコンマ演算子とは別のもので、「左から右」の順で評価を行うとはかぎりません。D コンパイラが関数の引数を評価する順番や、連想配列のキーを評価する順番は、特に決まっていません。このため、複数の式、たとえば ii++ を組み合わせて使用するときは、相互の副作用に注意してください。

演算子の優先順位の表にある [] は、配列または連想配列の参照を表します。連想配列の例は、第 1 章はじめにに記載されています。「集積体」と呼ばれる特殊な連想配列については、第 9 章集積体で説明します。演算子 [] を使って、固定サイズの C 配列にインデックスを付けることもできます。これについては、第 5 章ポインタと配列を参照してください。