编程不是自然语言,编程自有其内在逻辑。
左值引起的BUG
编译器经常给出类似这样的BUG提示:
“表达式必须是可修改的左值”
“非常量引用的初始值必须是左值”
看一下示例:
#include <iostream>
void f(int& x)
{}
int main()
{
short a = 1;
f((int)a);//非常量引用的初始值必须是左值
(int)a = 5;//表达式必须是可修改的左值
return 0;
}
左值是什么
"左值"到底是什么啊?左值其实就是可以放在赋值(=)左边的东西,右值就是可以放在右边的东西。
那什么可以放在赋值的左边呢?放在内存里的、有地址的东西都可以。
为什么类型转换不是左值
那么为什么“(int) a”不可以呢?这就涉及到自然语言和编程的差异:自然语言讲概念,编程则必须落到实体:内存或者寄存器。
自然语言的一个“数”是一个概念,有符号、无符号、存储长度都是没所谓的,只是概念上的一点限制。而对于编程,这些都要落实到具体的内存或寄存器上。
从一个short到int,直觉上就是一个概念变化嘛,a还是那个a,但是实际呢?
想一下,short和int长度都不一样,“(int)a”还能是原来那个a吗?
所以“(int)a”发生了什么?发生了一个临时变量,长度是4个字节,放在寄存器里,没有内存地址,用完了就扔了。
所以直接给“(int)a”赋值是没有意义的,程序的其他地方不可能引用这个只在寄存器里存在的对象(当然把寄存器里的临时变量赋值给一个有内存地址的变量是没问题的,这就是正常的赋值语句嘛)。
引用参数为什么也不可以呢?因为用引用的目的是像指针一样操作外面的对象,传一个临时变量进去完全没有意义(把引用理解成指针的另一种形式是完全没有问题的)。
即使是有符号、无符号转换,虽然长度不变,但逻辑上是一样的,都是生成一个临时对象。
类型转换究竟发生了什么
- 整数长度增加的转换会根据是否有符号进行不同的扩展方式:
无符号:前面扩展0
有符号:扩展符号位
效果:长度增加值不变。
- 整数长度不变、仅仅是有符号、无符号改变:
实际存储不变
结果是负值变成很大的正数或很大的正数变成负值。
- 长度变小的转换怎么做?
疯了,没事别这么做。
- 整数和浮点数转换:
浮点数的格式和整数完全不一样啊,一定要经过专门的指令来转换
总结
- 左值就是能赋值的对象
- 类型转换是临时对象,不是左值
(这里是结束)