値カテゴリ
C の式 (演算子、その引数、関数呼び出し、定数、変数名など) はそれぞれ2つの独立した性質、型および値カテゴリによって特徴付けられます。
すべての式は3つの値カテゴリ (左辺値、非左辺値オブジェクト (右辺値)、および関数指示子) のひとつに属します。
左辺値式
左辺値式は void 型を除くオブジェクト型の任意の式です。 オブジェクトを指示することもあります (左辺値が実際にはオブジェクトを指示しない場合は、それが評価されたとき、その動作は未定義です)。 別の言い方をすると、左辺値式はオブジェクトの識別性に評価されます。 この値カテゴリの名前は歴史的なものであり、 CPL プログラミング言語で代入演算子の左辺の被演算子として使用されたことを反映しています。
左辺値式は以下の左辺値文脈で使用できます。
- アドレス取得演算子の被演算子として (左辺値がビットフィールドを指示する場合または register 宣言された場合は除きます)。
- 前置および後置のインクリメントおよびデクリメント演算子の被演算子として。
- メンバアクセス (ドット) 演算子の左側の被演算子として。
- 代入および複合代入演算子の左側の被演算子として。
左辺値式が sizeof、 _Alignof、または上記の演算子以外の文脈で使用された場合、完全型の非配列の左辺値は左辺値変換が行われます (オブジェクトの値をメモリから読み込む処理をモデル化しています)。 同様に、配列の左辺値は、 sizeof、 _Alignof、アドレス取得演算子、または文字列からの配列初期化以外の文脈で使用された場合、配列からポインタへの変換が行われます。
const、 volatile、 restrict 修飾子およびアトミック型の意味論は左辺値にのみ適用されます (左辺値変換はこれらの修飾子およびアトミック性を取り除きます)。
以下の式は左辺値です。
- 識別子 (関数の引数を含みます) (それらが指示されたオブジェクトとして宣言された (関数や列挙定数でない) 場合)
- 文字列リテラル
- (C99) 複合リテラル
- 式が左辺値の場合の、その式を括弧で囲ったもの
- 左側の引数が左辺値の場合の、メンバアクセス (ドット) 演算子の結果
- ポインタを通したメンバアクセス
->演算子の結果 - オブジェクトへのポインタに間接参照 (単項
*) 演算子を適用した結果 - 添字演算子 (
[]) の結果
変更可能な左辺値式
変更可能な左辺値は、 const 修飾されていない、 (構造体または共用体の場合は) const 修飾されたメンバを再帰的にも持たない、非配列な、完全型の、任意の左辺値式です。
変更可能な左辺値式だけが、インクリメントおよびデクリメントの引数として、および、代入および複合代入演算子の左側の引数として、使用できます。
非左辺値オブジェクト式
非左辺値オブジェクト式 (いわゆる右辺値) は、オブジェクトを指示するのではなく、オブジェクトの識別性や記憶域の場所のない値を指示する、オブジェクト型の式です。 非左辺値オブジェクト式のアドレスを取ることはできません。
以下の式は非左辺値オブジェクト式です。
- 整数定数、文字定数、および浮動小数点定数。
- 左辺値を返すと規定されていないすべての演算子、例えば
- あらゆる関数呼び出し式
- あらゆるキャスト式 (似たような見た目の複合リテラルは左辺値であることに注意してください)
- 非左辺値の構造体または共用体に適用されたメンバアクセス (ドット) 演算子 (例:
f().x、(x,s1).a、(s1=s2).m) - すべての算術、関係、論理、およびビット単位の演算子
- インクリメントおよびデクリメント演算子 (ノート: C++ では前置形式は左辺値です)
- 代入および複合代入演算子 (ノート: C++ では左辺値です)
- 条件演算子 (ノート: C++ では左辺値となることもあります)
- コンマ演算子 (ノート: C++ では左辺値となることもあります)
- アドレス取得演算子 (たとえ単項
*演算子の結果に適用されて中和される場合でも)
特別なケースとして、 void 型の式は、表現を持たず記憶域を必要としない値を生成する、非左辺値オブジェクト式であると仮定されます。
配列型のメンバを持つ (ネストした場合を含みます) 構造体または共用体の右辺値は一時的な生存期間を持つオブジェクトを実際に指示することに注意してください。 このオブジェクトは、その配列のメンバをインデックスすることによってまたはその配列メンバの配列からポインタへの変換によって取得したポインタを通した間接参照によって形成した左辺値式を通して、アクセス可能です。
関数指示子式
関数指示子 (関数宣言によって導入された識別子) は関数型の式です。 アドレス取得演算子、 sizeof、および _Alignof 以外の文脈で使用されたとき、関数指示子は常に関数の非左辺値ポインタに変換されます (sizeof と _Alignof は関数に適用するとコンパイルエラーを生成します)。 関数呼び出し演算子は関数指示子自体ではなく関数へのポインタに対して定義されることに注意してください。
参考文献
- C11 standard (ISO/IEC 9899:2011):
- 6.3.2.1 Lvalues, arrays, and function designators (p: 54-55)
- C99 standard (ISO/IEC 9899:1999):
- 6.3.2.1 Lvalues, arrays, and function designators (p: 46)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.2.2.1 Lvalues and function designators
関連項目
値カテゴリ の C++リファレンス
|