“左值和右值”的思考

起源于C语言

左值和右值都是从继承C语言继承过来的,那么为什么C语言中要创造“左值和右值”,在C语言中又是怎么定义的呢?

在Kernighan Kernighan和Ritchie创造了左值这个术语来区分某些表达与其他表达。在《The C Programming Language 》中他们写到"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.",换句话说运算符“=”左边一定是个左值,它最初只是用来做一些区分,编译器报错的时候,我们也会常见到它的身影。

例如:

int n;
n = 4;

这里n指向一个整形对象,是一个右值,所以没有错。但是假如我们换成:

4 = n;

编译器就会报错:“error: lvalue required as left operand of assignment 4 = n”;这里4是只是一个常量,不能作为一个左值。

所以,左值和右值可以帮助我们和一些表达式做一些很好的区分,在C语言中,不懂“左值和右值”好像并不影响我们编程,但是它有助于我们深入理解一些内置运算符。

基本的概念

我们已经有几种常用的运算符用到左值,下面我们来看看:

int n;
n = 4;

赋值运算符需要一个(非常量)左值作为左侧运算对象,得到的结果仍然是一个左值。

int n = 1, m = 2;
n = m + 1; // success
m + 1 = n; // error 

因为“+”运算符等级高于“=”,所以m+1 = n 等价于 (m + 1) = n ,这里报错,因为m + 1是右值。

int n, *p;
...
p = &n;    // ok
&n = p;    // error: &n is an rvalue

这里,“&”地址运算符得到的结果也是右值。

int a[N];
int *p = a;
...
*p = 3;     // ok
*(p + 1) = 4;    // ok

这里,“*”解引用运算符得到的结果是左值,所以正确。

到这里,我们可以看出,当一个对象被用作右值的时候,用的是对象的值(内容),而对象被用作左值的时候,用的是对象的地址,如果一个对象没有地址(无法取地址),也就无法作左值。

左值和右值的转化

int a = 1;     // a is an lvalue
int b = 2;     // b is an lvalue
int c = a + b; // + needs rvalues, so a and b are converted to rvalues
               // and an rvalue is returned

一般来说,需要右值的地方可以用左值来代替,但是不能把右值当成左值来用,但是这里有个例外,下面我们来看:

int i = 42;
int &&rr2 = i; // error can't bind a rvalue ference to an lvalue
int &&rr2 = i *42; // ok

我们可以将一个右值引用绑定到一个表达式上,但是不能讲一个右值引用绑定到一个左值上。

参考:

  1. http://ieng9.ucsd.edu/~cs30x/Lvalues%20and%20Rvalues.htm
  2. http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c/
  3. <C++ Primer>
原文地址:https://www.cnblogs.com/vczf/p/6839118.html