[转] 左值和右值

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

http://homepage.ntlworld.com/dmjones/cbook1_2.pdf

时间: 2024-10-12 23:19:56

[转] 左值和右值的相关文章

(C++)关于i++和i++的左值、右值问题

1.什么是左值和右值? 左值就是出现在表达式左边的值(等号左边),可以被改变,他是存储数据值的那块内存的地址,也称为变量的地址: 右值是指存储在某内存地址中的数据,也称为变量的数据. 左值可以作为右值,但右值不可以是左值. 因此也只有左值才能被取地址. 2.举两个问题: int i = 0; (i++)+=i; //错误 (++i)+=i; //正确 int *ip = &(i++); //错误 int *ip = &(++i); //正确 3.为什么i++不能作左值? 我们来看i++和i

c++中的左值与右值

++(a++) a++相当于 int a; { int temp=a; a++; teturn temp; } 所以我们可以将++(a++)看成++temp;而temp 显然是一个右值,所以不能用啊~~ L-value中的L指的是Location,表示可寻址.The "l" in lvalue can be though of as locationR-value中的R指的是Read,表示可读.The "r" in rvalue can be thought of

C 语言中的左值和右值。以及对比数组名和指针取数组元素的区别。

左值:出现在赋值符左边的符号有时称为左值. 右值:出现在赋值符右边的符号有时称为右值. 编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址.相反,存储于变量中的值(它的右值)只有在运行时才可知.如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器. 可以看到,每个符号的地址在编译时可知. 对比一下几个式子: //常规变量 int a=1;//这里a作为左值出现,代表的是地址,即在a表示的这个内存地址存入数值1.即a代表的内

C++11之右值引用:从左值右值到右值引用

C++98中规定了左值和右值的概念,但是一般程序员不需要理解的过于深入,因为对于C++98,左值和右值的划分一般用处不大,但是到了C++11,它的重要性开始显现出来. C++98标准明确规定: 左值是可以取得内存地址的变量. 非左值即为右值. 从这里可以看出,可以执行&取地址的就是左值,其他的就是右值. 这里需要明确一点,能否被赋值不是区分C++左值和右值的区别. 我们给出四个表达式: string one("one"); const string two("two&

4.1 中的左值和右值

摘要:  引自---http://www.cnblogs.com/catch/p/3500678.html 左值 (lvalue)和右值 (rvalue) 是 c/c++ 中一个比较晦涩基础的概念,有的人可能甚至没有听过,但这个概念到了 c++11 后却变得十分重要,它们是理解 move, forward 等新语义的基础. 左值右值的定义 左值与右值这两概念是从 c 中传承而来的,在 c 中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?

c++11の的左值、右值以及move,foward

左值和右值的定义 在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值.有些变量既可以当左值又可以当右值.进一步来讲,左值为Lvalue,其实L代表Location,表示在内存中可以寻址,可以给它赋值(常量const类型也可以寻址,但是不能赋值),Rvalue中的R代表Read,就是可以知道它的值.例如: int a=3; a在内存中有地址,而3没有,但是可以read到它的值. 3=4; 这个是错误的,因为3的内存中没有地址,不能当作左值. 下面这个语句不容易出错 a++

c/c++左值和右值

C/C++中的变量有左值和右值之分,他们的区别主要如下: (1)左值可以放在赋值号 = 的左右两边,右值只能放在赋值号 = 的右边 (2)在C语言中,有名字的变量即为左值:而函数的运行结果或表达式中间变量即为右值 (3)对于内嵌类型(基本类型,即built-in types),右值是不可以被更改的,也不可以被const,volatile所修饰: 对于自定义类型,右值却可以通过它的成员函数来进行修改. (4)左值也可以作为右值表达式,变量可以是左值,也可以为右值,但常量只能是右值. (5)右值只能

C++中的左值和右值

左值和右值的定义 在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值.有些变量既可以当左值又可以当右值.进一步来讲,左值为Lvalue,其实L代表Location,表示在内存中可以寻址,可以给它赋值(常量const类型也可以寻址,但是不能赋值),Rvalue中的R代表Read,就是可以知道它的值.例如: int a=3; a在内存中有地址,而3没有,但是可以read到它的值. 3=4; 这个是错误的,因为3的内存中没有地址,不能当作左值. 下面这个语句不容易出错 a++