i++和++i的区别
i++和++i都是自增运算符,如果你不细究的话,可以简单地理解为(i++)是先运算再对i本身自增;同理(++i)是先对i本身进行自增然后进行运算。
它们的工作机制究竟是怎样的呢?
那我们可以解析一下它的汇编指令(通过gcc)
i++; ++j;
我们可以看到当他们单独执行时,编译器都会对他们对应的内存地址的内容进行+1操作。
#include<bits/stdc++.h>
using namespace std;
int main(){
int i = 0,j = 0;
i+= (i++) + (++i);
j+= (++j) + (j++);
cout<<"i += (i++) + (++i) i = "<<i<<endl;
cout<<"j += (++j) +( j++) j = "<<j<<endl;
}
这是相应的结果,通过结果我们可以发现当他们初始为0时得到的结果是不一样的,同样我们看一下相应的汇编指令
i+=(i++)+(++i)的指令
0x000000000040154b <+27>: mov eax,DWORD PTR [rbp-0x4]
0x000000000040154e <+30>: lea edx,[rax+0x1]
0x0000000000401551 <+33>: mov DWORD PTR [rbp-0x4],edx
0x0000000000401554 <+36>: add DWORD PTR [rbp-0x4],0x1
0x0000000000401558 <+40>: mov edx,DWORD PTR [rbp-0x4]
0x000000000040155b <+43>: add eax,edx
0x000000000040155d <+45>: add DWORD PTR [rbp-0x4],eax
你可能看的不是很懂,我简单的说一下它做了什么。
根据运算符优先级,它首先时生成i++的指令也就是前三条
你可以简单地理解为 int temp1 = i ; i = i + 1 ;就是他先将i的值放到一个临时的变量中(实际上是一个寄存器),再将内存中i的值进行+1操作,以后进行加法运算的就是这个temp1。
然后就是执行(++i)操作,你可以把他理解为i= i+1;就是再将内存中的i自增1.
第三个就是执行(i++)和(++i)中间的加法操作了,就是temp1 = temp1 + i;
最后一步就是+=这个运算符了,当它是最后一个运算符时,你就可以看成i = i + …
综上我们可以得到:
int temp1 = i;//temp1 = 0
i = i + 1;//i = 1
i = i + 1;//i = 2
temp1 = temp1 + i;//temp1 = 2
i = i + temp1;//i = 4
我们再用同样的方法来看j += (++j) + (j++);
j += (++j) + (j++);
0x0000000000401560 <+48>: add DWORD PTR [rbp-0x8],0x1
0x0000000000401564 <+52>: mov eax,DWORD PTR [rbp-0x8]
0x0000000000401567 <+55>: lea edx,[rax+0x1]
0x000000000040156a <+58>: mov DWORD PTR [rbp-0x8],edx
0x000000000040156d <+61>: mov edx,DWORD PTR [rbp-0x8]
0x0000000000401570 <+64>: add eax,edx
0x0000000000401572 <+66>: add DWORD PTR [rbp-0x8],eax
第一步执行++j
j = j + 1;//j = 1
第二步执行(j++)
int temp2 = j;//temp2 = 1
j = j + 1;//j = 2
第三步相加
temp2 = j + temp2;//temp2 = 3
第四步j += temp2;
j = j + temp2;j = 5
为什么是这样的执行顺序呢?这就涉及到运算符的优先级问题,以及从左到右的压栈规则,就是只有当即将入栈的运算符等级不高于栈顶的运算符等级时才进行运算,(或者它是最后一个运算符)
对于 a += (b++) + (++c);//我们不考虑括号哈
1.我们将操作数a压入栈1 (操作数存放的栈),
2.我们将运算符+=压入栈2(运算符存放的栈)
3.b压入栈1
4.++压入栈2//++的运算符等级高于+=,不执行运算操作
5.+压入栈2,此时+的等级低于++执行 执行b++操作,并弹出++ 和 b(其实是先判断,再将+压入栈。b++操作,它会将temp临时变量(值为运算前的b 的值)压入栈1中),此时栈2中栈顶为+。
6.++压入栈2//++高于栈顶的+,不执行
7.c压入栈1,此时没有新的运算符执行++c操作,再执行temp= temp+c,最后a+=temp
这就解释了为什么下面几个表达式的值不一样
#include<bits/stdc++.h>
using namespace std;
int main(){
int i = 0,j = 0,k = 0,m = 0,zero = 0;
i += (++i) + (i++);
j += (++j) + 0 + (j++);
k += (++k) + zero + (k++);
m += (++m) + 1 +(m++);
cout<<"i += (i++) + (++i) i 的值为 "<<i<<endl;
cout<<"j += (++j) + 0 + (j++) j 的值为 "<<j<<endl;
cout<<"k += (++k) + zero + (k++) k 的值为 "<<k<<endl;
cout<<"m += (++m) + 1 + (m++) m 的值为 "<<m<<endl;
}
这里注意一下当你写a + 0 + b时,编译器会自动将零优化掉,变成a + b
从上面的结果中我们可以看到
i += (++i) + (i++);
j += (++j) + zero + (j++);//zero = 0
他们的值不一样i = 5,而 j = 4;这是因为编译器先执行了 (++j) + zero,是的 (j++) 中的 +1没有被前面的 ++j 得到
因此就有
i += (++i) + (i++);i = 5;
i += (++i) + 1 + (i++);i = 5; 这两个式子结果一样
以上是我对i++,和++i的一些心得,可能会有一些错误欢迎指出告诉我哈。以上是对gcc的,Javac会不一样
比如说javac 中i += (i++) + (++i);i = 2;
其实在你自己写代码的过程中,完全可以避开这样写,这样写的唯一作用就是装B,除了面试时可能会有,平时根本不会出现(写项目时这样写,你就等着回家吃泡面吧…)。