看到一系列前缀++和后缀++和cout的东西,首先我要说的是,这根cout运算符没什么关系,可以试下printf是一样的。
有一点原则是:首先要计算后面的,原因跟汇编有关。所以函数的入口参数都是从右边算到左边。
就像c++的构造函数的:初始化,其实先初始化的是最右边的变量。
先说几个例子:
int i=0;
(1)cout<<i<<i++<<endl;
(2)cout<<i++<<i<<endl;
(3)cout<<++i<<i<<endl;
(4)cout<<i<<++i<<endl;
说下计算思想:先算靠近endl(最右边的)。
然后注意一点:
(++i表示取i的地址,对他的内容进行+1操作,然后把值放在寄存器。
i++表示取i的地址,把它的值装入寄存器,然后对内存中i的值执行+1操作。
由于我们使用的都是寄存器的值。所以有这样的结果。)
所以(1)1 0(2)0 1(3)1 1(4)1 1(不会真有人一个一个输进去试吧?)
以上的比较简单,但是有难得了
(1)cout << i++ << i++ << endl;
(2)cout << i++ <<++ i << endl;
(3)cout << ++i << i++ << endl;
(4)cout << ++i << ++i << endl;
有人无聊可以自己猜想下结果,然后vs一下,应该对不过半数吧?
再补充个概念:
左值和右值。左值就是可以出现在表达式左边的值(等号左边),可以被改变,它是存储数据值的那块内存的地址,也成为变量的地址;右值是指存储在某内存地址中的数据,也称为变量的数据。
左值可以作为右值,但是右值不可以是左值。
i++不能当做左值使用,++i可以当左值使用。
意思可以这样理解:i++是像函数一样可以返回的,它不可以被赋值。而++i(需要特别注意)是直接更新当前内存。
另外cout的执行过程可以这样理解:首先从右到左计算,最后再一次性把这坨东西显示到UI上。
所以,以后遇到i++,可以认为它返回了,也就是说i++输出的值是基于之前运算过的,不会再变(因为它已经更新的寄存器里面了)。而++i执行了自己的自增运算,但是在cout时,最后还要访问一遍自己的内存,也就是说它显示了自己最新的数据。
我拿cout<<++i<<i++<<++i<<endl;举例:
首先看到最右边的++i。
(1)i初始为0,经过++i,内存被更新了i为1了,但是并没有被cout显示到UI上
(2)到第二个i++,此时读i的值是1,直接返回i的值(cout已经记住了i为1,要默默念,默默念)。之后再给i的内存中的原来的值(为1)加上1,此时内存的值为2
(3)到最左边的++i。读i的内存,i为2,此时给内存值直接加上1,内存值为3.
(4)要cout了,从左向右看。第一个没有疑问是3,第二个刚才说过了(相当于返回1,不懂就看第(2)步),第三个,此时要访问i内存,i的内存是3
(5)输出3 1 3
可以用这种分析方法了专门针对无聊的cout输出。