値カテゴリ
C言語における各式(引数を伴う演算子、関数呼び出し、定数、変数名など)は、型と値カテゴリという2つの独立した特性によって特徴付けられます。
すべての式は、lvalue、非lvalueオブジェクト(rvalue)、関数指示子という3つの値カテゴリのいずれかに属します。
目次 |
[編集] Lvalue式
Lvalue式とは、void型以外のオブジェクト型を持つあらゆる式で、オブジェクトを指す可能性のあるものです(lvalueが評価されるときに実際にオブジェクトを指さない場合、その動作は未定義です)。言い換えれば、lvalue式はオブジェクトの同一性に評価されます。この値カテゴリの名前("left value")は歴史的なものであり、CPLプログラミング言語における代入演算子の左オペランドとしてlvalue式が使用されたことを反映しています。
Lvalue式は以下のlvalueコンテキストで使用できます。
- アドレス演算子のオペランドとして(ただし、lvalueがビットフィールドを指す場合や、register宣言されている場合を除く)。
- 前/後インクリメントおよびデクリメント演算子のオペランドとして。
- メンバーアクセス(ドット)演算子の左オペランドとして。
- 代入および複合代入演算子の左オペランドとして。
lvalue式がsizeof、_Alignof、または上記の演算子以外のコンテキストで使用される場合、完全型の非配列lvalueはlvalue変換を受けます。これは、オブジェクトの値のメモリロードをモデル化します。同様に、配列lvalueは、sizeof、_Alignof、アドレス演算子、または文字列リテラルからの配列初期化以外のコンテキストで使用される場合、配列からポインタへの変換を受けます。
const/volatile/restrict修飾子およびアトミック型のセマンティクスはlvalueにのみ適用されます(lvalue変換は修飾子を剥奪し、アトミック性を削除します)。
以下の式はlvalueです。
- 関数ではなくオブジェクトを指すように宣言された識別子(関数仮引数を含む)
- 文字列リテラル
- (C99) 複合リテラル
- 括弧で囲まれていない式がlvalueである場合、括弧で囲まれた式
- メンバーアクセス(ドット)演算子の左引数がlvalueである場合の結果
- ポインタによるメンバーアクセス
->演算子の結果 - オブジェクトへのポインタに適用された間接参照(単項
*)演算子の結果 - 添字演算子(
[])の結果
[編集] 変更可能なlvalue式
変更可能なlvalueとは、完全型で非配列型であり、const修飾されておらず、かつ、構造体/共用体である場合は、再帰的にconst修飾されたメンバーを持たないlvalue式のことです。
変更可能なlvalue式のみが、インクリメント/デクリメントの引数として、および代入演算子と複合代入演算子の左引数として使用できます。
[編集] 非lvalueオブジェクト式
rvalueとして知られる非lvalueオブジェクト式は、オブジェクトではなく、オブジェクトの同一性や格納場所を持たない値を指すオブジェクト型の式です。非lvalueオブジェクト式のアドレスを取ることはできません。
以下の式は非lvalueオブジェクト式です。
- 整数、文字、および浮動小数点定数
- lvalueを返すと明示されていないすべての演算子(以下を含む)
- あらゆる関数呼び出し式
- あらゆるキャスト式(ただし、類似して見える複合リテラルはlvalueであることに注意)
- 非lvalue構造体/共用体に適用されるメンバーアクセス(ドット)演算子、f().x、(x,s1).a、(s1=s2).m
- すべての算術、関係、論理、およびビットごとの演算子の結果
- インクリメントおよびデクリメント演算子の結果(注意: C++では前置形式はlvalue)
- 代入演算子の結果(注意: C++ではlvalue)
- 条件演算子(注意: C++では、第2および第3オペランドが同じ型のlvalueである場合、lvalue)
- コンマ演算子(注意: C++では、第2オペランドがlvalueである場合、lvalue)
- 単項
*演算子の結果に適用されても無効化されないアドレス演算子
特殊なケースとして、void型の式は、表現を持たず、記憶域を必要としない値を生成する非lvalueオブジェクト式であると仮定されます。
配列型のメンバー(入れ子になっている可能性もある)を持つ構造体/共用体のrvalueは、実際には一時的な生存期間を持つオブジェクトを指すことに注意してください。このオブジェクトは、配列メンバーをインデックス付けすることによって形成されるlvalue式、または配列メンバーの配列からポインタへの変換によって得られたポインタを介した間接参照によってアクセスできます。
[編集] 関数指示子式
関数指示子(関数宣言によって導入される識別子)は、関数型の式です。アドレス演算子、sizeof、および_Alignof(後者2つは関数に適用されるとコンパイルエラーを生成します)以外のコンテキストで使用される場合、関数指示子は常に非lvalue関数ポインタに変換されます。関数呼び出し演算子は、関数指示子自体ではなく、関数へのポインタに対して定義されていることに注意してください。
[編集] 参照
- C17標準 (ISO/IEC 9899:2018)
- 6.3.2.1 Lvalues、配列、および関数指示子 (p: 40)
- C11標準 (ISO/IEC 9899:2011)
- 6.3.2.1 Lvalues、配列、および関数指示子 (p: 54-55)
- C99標準 (ISO/IEC 9899:1999)
- 6.3.2.1 Lvalues、配列、および関数指示子 (p: 46)
- C89/C90標準 (ISO/IEC 9899:1990)
- 3.2.2.1 Lvaluesおよび関数指示子
[編集] 関連項目
| C++ ドキュメント 値カテゴリについて
|