C言語において、lvalueとrvalueの違いは、代入演算子を適用できる式を定義するための基礎として歴史的に生まれました。Lvalue(left value)は、メモリ内の特定の場所を占め、アドレス取得(&)の操作を適用できるオブジェクトを指します。Rvalue(right value)は、特定のアドレスを持たない一時的な値です。この違いは、代入の仕組み、関数への引数の渡し方、およびコンパイラの最適化を理解するために重要です。
問題は、lvalueのみに許可されている操作(例えば代入)をrvalueに対して実行しようとした場合に発生します。これにより、コンパイルエラーや実行時に不明瞭なバグが発生する可能性があります。
解決策は、lvalueとrvalueの使用コンテキストを明確に理解することです。例:
int x = 5; int y; y = x; // xはlvalueかつrvalue、yはlvalue y = x + 1; // x + 1はrvalue(アドレス取得不可) // &xは正しい、&(x + 1)はエラー
主な特徴:
任意の式(例えば(x + y))からアドレスを取得できますか?
いいえ、lvalueのみがアドレスを持ちます。例えば、式(x + y)はrvalueです。
int z = 3, y = 7; int *p = &(z + y); // コンパイルエラー
定数に値を代入しようとした場合(例えば、5 = x)に何が起こりますか?
コンパイルエラーが発生します。リテラル5はrvalueであり、lvalueとして使用できません。
5 = x; // エラー:左側のオペランドはlvalueではありません
関数はlvalueを返すことができますか?
通常の関数はrvalueを返しますが、参照(例えばC++で)を返す場合は、これはlvalueです。Cではrvalueのみの返却が許可されています。
int foo() { int x = 5; return x; } // rvalueが返される
プログラマーが一時的な式の結果(a + b)からアドレスを取得しようとしました:
int *p = &(a + b);
利点:
欠点:
プログラマーが意識的にlvalueとrvalueを区別します。構文と意味論が許す場所でのみ値を使用します:
int x = 7; int *p = &x; // 正しい
利点:
欠点: