左值与右值
目录

在大多数语言中,我们对于取变量地址和变量值(变量内容)的表达是不加区分的, 都使用变量的符号来表示,然后由编译器根据上下文推断变量到底是取地址还是取值。 C语言就是这样。例如:

X = Y;

上面一个赋值语句里,X取得的是其所代表对象的地址,这被称为左值(L-value)。 Y取得的是其所代表对象的值,这被称作右值(R-value)。 所以同样表达为对象的符号(X,Y),但是针对其在表达式中不同的位置会进行不同的解释。 左值对象所取得的地址在编译时就能确定,而右值所取得的值只有在运行时才能确定。

换句话说,读取动作就是右值运用(rvalue usages),写动作是左值运用(lvalue usages)。 这些术语来自编译器研发团队,一般而言,lvalue对象可以被修改,rvalue对象不可以被修改。

想要作为左值的对象必须能够取得其地址,同时能够取得地址的对象也必定能够取得值。 而想要作为右值的对象就没那么严格了,只要能够取得值的对象就可以。 所以,能够做左值的对象一定能做右值

要求 举例
左值 取地址和取值 变量
右值 取值 变量,数字常量,字符串常量,enum

n = 1;  // ok

中,n可以获得其对象的地址,因此n可以作为左值。1可以取得其值1,可以是右值。但是在

1 = n;  // error

中,n在右边可以取得其对象的值,符合条件,但是常数1不能取得其地址(没有对象),所以不能作为左值。

数学运算符 + - × /

在其它的表达式中,操作符两边可能就没有那么严格了,如加法表达式:

x + y

只要求xy是右值即可。但是,加法表达式的结果也是右值,因此下面表达式不成立:

x + y = z; //error

因为x+y结果是右值,不能作为等号的左值。

引用 &

单目操作符&的操作对象要求是左值,因此&n成立,&3不成立。 而且&的结果也是右值,因此:

int n, *p;
...
p = &n;  // ok
&n = p;  // error

指针 *

&操作完全相反,*可以接受一个右值,并且返回一个左值。 因此以下成立:

*(p+1) = 4; // ok

数组名

数组名这个对象比较特殊,它已经表示了一个数组的首地址且不可更改。 进一步讲,数组变量并没有分配内存空间,它直接就是一个编译时确定的地址。 因此,数组名不能作为左值出现在等式右边。

常量char作为右值

常量char是没有右值的,当其作为右值时,其被强制转换为int。 这从sizeof('a')的结果中可以看出来。

参考:

发表评论