http://www.cnblogs.com/dejavu/archive/2012/09/02/2667640.html#commentform
<C/C++> 左值和右值, L-value和R-value
一直以为左值是可以出现在赋值表达式左边(the left side of an assignment expression)的值,Left-value;右值即Right-value.
今天看到一个说法,觉得有点味道:
L-value中的L指的是Location,表示可寻址. The "l" in lvalue can be thought of as location.
R-value中的R指的是Read,表示可读. The "r" in rvalue can be thought of as "read" value.
为了寻找lvalue术语的出处,先是<The C Programming Language>中,Kernighan and Ritchie写道:
"An object is a manipulatable region of storage; an lvalue is an expression referring to an object.
...
The name 'lvalue' comes from the assignment expression E1 = E2 in which the left operand E1 must be an lvalue expression."
然后我又不畏艰险,硬着头皮翻看C99标准和<The New C Standard>这本书,想从中查找点蛛丝马迹:
The name “lvalue” comes originally from the assignment expression E1 = E2, in which the left operand E1 is required to be a (modifiable) lvalue.
Or left value of assignment. The right value being called the rvalue. This is translator writers’ terminology that the C Standard committee has adopted....
It is perhaps better considered as representing an object “locator value”.
...
What is sometimes called “rvalue” is in this International Standard described as the “value of an expression”.
似乎缺乏一个统一且明确的标准定义. 不过可以看出,左值原来定义的确跟赋值表达式左侧有关,但更好的定义是"内存中,有特定位置(地址)的东西"或"指向一个确定对象的东西".
许多语言中,一个对象(object)只允许通过表达式(assignment)来修改.而C语言更灵活,它允许可以通过操作符(operator)来修改对象的值,而不仅仅是通过表达式(如++自增操作符).这就让清楚地区分左值和右值的含义变的很重要,如
int a = 10;
++(a++); //error!
编译器(gcc)会报错:error: non-lvalue in increment (非左值自增)
如果能清楚的理解,左值(lvalue)是一个"拥有一个可以确定的地址(指向一个对象)"的标识符或表达式,而右值(rvalue)只是一个值,并不一定指向一个对象.那这个问题就简单了:
(a++)表达式 是先将a的值做为整个表达式的值返回,再将a自增1.那么,(a++)表达式的值并不指向一个对象(不拥有一个内存地址),因为它类似
{
int temp = a;
a = a+1;
return temp;
}
temp是临时值(如某个寄存器),它并不指向一个对象(temp并没有分配实际的地址).所以(a++)表达式不是左值!之后,++(a++)相当于对一个右值(非左值)进行自增(++temp)当然是不合理的!
但是,注意!后缀增量表达式返回值一定是个非左值,但前缀增量表达式呢? 前缀增量表达式的返回值对于C和C++是不同的:
int a = 10;
(++a)++; //C++ ok,C error!
++(++a); //C++ ok,C error!
(a+=1)+=1; //C++ ok,C error!
对于上述代码,gcc是报错,而g++是通过!
原因在于,C中,前缀增量表达式(prefix increment)返回的是非左值(C标准6.5.3.1 The expression ++E is equivalent to (E+=1).并且在6.5.16 An assignment expression has the value of the left operand after the assignment, but is not an lvalue. )(这也说明了C语言中(a=1)=2,这样的连用是错误的!)
但在C++中,已经明确定义前缀增量表达式返回值为一个左值(C++标准5.3.2.1 The value is the newvalue of the operand; it is an lvalue.).所以对(++a)再做一次前++或后++没问题.(而且赋值表达式返回也是左值,所以(a=1)=2连用没问题)
另外,
在C中,一个表达式要么是左值要么是非左值,没有右值说法,直到C++时,右值才被正名.
左值不一定是可以修改的值,如一个const对象是左值,但不能被修改(non-modifiable lvalue).
右值可以是左值和非左值.
其他参考:
http://www.cppblog.com/cc/archive/2012/06/27/7619.html
http://eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues
http://stackoverflow.com/questions/3572753/difference-between-cs-expression-and-cs-expression