了解左值右值之前我们先来了解一下存储的层次结构
举个简单的例子,假设我们在农村,没有自来水,每天用水都得去村里距离2km的水井打水用。假如我们要刷个牙,要跑2km打水,洗个脸,又要去水井打水,这样的效率非常低下。于是我们在家门口建了一个大水缸,能储存好多的水,每天只需要从井里打水把水缸填满,这样我们需要用水的时候只需要在家门口打水即可,这样就大大的提高了效率。磁盘就相当于水井,里面有很多的容量,但是我们要使用的话速度非常慢,RAM(内存)就相当于水缸,容量一般,但是我们使用的话要比在水井打水快速得到多,CPU就相当于我们日常需要用水的行为,比如说刷牙洗脸洗菜。我们在电脑里下载的那些软件都存储在磁盘里,当我们打开的时候,就进入到了内存,供CPU使用计算等一系列操作。CPU进行计算的空间叫做寄存器,需要的数据都保存在寄存器里面。
左值和右值的概念
按字面意思,通俗地说。以赋值符号 = 为界,= 左边的就是左值(lvalue),= 右边就是右值(rvalue)。
lvalue - 代表一个在内存中占有确定位置的对象(换句话说就是有一个地址)。
rvalue - 通过排他性来定义,每个表达式不是lvalue就是rvalue。因此从上面lvalue的定义,rvalue是在不在内存中占有确定位置的表达式,而是存在在寄存器中。
所有的左值(无论是数组,函数或不完全类型)都可以转换成右值。
为了更深入的理解,我们来看一下linux里面汇编语言。
第一张的图片相信大家都看得懂,下面为大家讲解第二章汇编语言的含义。main下面就是main函数的内容,我们从第一个movl看起,%rbp是栈顶的意思,先把1放到距离栈顶-12的位置,然后把2,3分别放到距离栈顶-8,-4的位置,自此p1的赋值操作完成。然后进行c=a+b前,先把a,b放到寄存器里面,我们可以看到movl -12(%rbp),%edx,movl -8(%rbp),%eax。这两行就是把距离栈顶-12,-8位置的值放入寄存器,然后进行add操作。addl %edx,%eax的意思就是把这两个寄存器里的值相加,保存在eax中,紧接着把eax的值转移到-4(%rbp)也就是c的内存中去。
所以我们可以思考为什么a+b=c不能通过编译呢?因为a+b的值是存储在寄存器中的,不是在内存中的,左值一定是在内存中有确定位置的,所以a+b不能作为左值。所有的左值都可以转化成右值,因为可以把内存的东西移到寄存器作为右值使用,反之不行。