首页 > 代码库 > C语言中不可告人的(i++)+(i++)+(i++)!!!你发现了吗?
C语言中不可告人的(i++)+(i++)+(i++)!!!你发现了吗?
今天有个小学妹问我c语言中关于自增自减的问题,发现C语言的水真的深。
先看一段代码吧。
#include <stdio.h> void main(){ int i=5,j=5,p,q; p=(i++)+(i++)+(i++); //1 q=(++j)+(++j)+(++j); //2 printf("%d,%d,%d,%d",p,q,i,j); }
首先先解释p的值吧。
是不是很多在学习C语言的小伙伴觉得p应该等于18呢?
第一种:p = 15
如图中所见,在vc环境下p的值为15,那么只可能有一种解释:
p=5+5+5=15
在VC6.0中,第一个子表达式i++求完值后,其它子表达式中出现的变量i的值还没有改变,依然是5。
表达式(i++) + (i++) + (i++)的值为15(5+5+5),求完值后,变量i会执行自增操作3次,其值会变成8。所以最终的结果为15和8。
**第二种:p = 18
在gcc和dev c++环境下p的值为18,不难理解:
p = 5+6+7=18
由于"i++"是先加后自增,所以是从5开始边加边自增,最终的结果为18和8。
严格意义上来说,这个表达式不“合法”。严格地说C语言程序中不能出现类似的表达式,它是非法的,虽然它能通过编译系统的检查并也能输出一个结果。
再来解释下q为什么是22(TC环境下是24(8+8+8))吧。
用VC中的debug反汇编:
q=(++j)+(++j)+(++j);
0040102F mov eax,dword ptr [ebp-4] //把j的值传到寄存器EAX,dword ptr [ebp-4]存放的是变量j
00401032 add eax,1 //EAX加1
00401035 mov dword ptr [ebp-4],eax //EAX的值传到变量j,这两步实现第一个++j,此时j=6
00401038 mov ecx,dword ptr [ebp-4] //把j的值传到寄存器ECX
0040103B add ecx,1 //ECX加1
0040103E mov dword ptr [ebp-4],ecx //ECX的值传到变量j,这两步实现第二个++j,此时j=7
00401041 mov edx,dword ptr [ebp-4] //把变量j传到EDX
00401044 add edx,dword ptr [ebp-4] //再加上j的值,这一步实现了第一个加号的加法运算,内存中j变量的值仍是7
00401047 mov eax,dword ptr [ebp-4] //把j的值传到寄存器EAX
0040104A add eax,1 //EAX加1
0040104D mov dword ptr [ebp-4],eax //把EAX的值传送到变量j中,此时,变量j在内存中的值是8
00401050 add edx,dword ptr [ebp-4] //EDX加上j的值,EDX中存放的是前面的第一个加法运算的结果14,最后EDX的值为22
00401053 mov dword ptr [ebp-8],edx //把运算结果传到内存中变量q的地方,所以最后变量q为22
可能有很多小白看不太懂上述的解释 q=7+7+8=22 C语言的深水在这里就可以体现了,在C语言中,加法从左到右运算,先算前两个加数的和,
再和第三个相加的过程中,他会先把前两个括号内的东西执行完成后,再执行括号外的加法,也就是(7+7)+8=22。 如果是4个++j连续的话,
结果就应该是 7+7+9+9=32 。
亲爱的你们懂了吗?
ps: 在php语言中,测试上述代码: ```
<?php $a = 5; $b = 5; $p = ($a++)+($a++)+($a++); $q = (++$b)+(++$b)+(++$b); echo $p; echo $q; echo $a; echo $b;
得到的18和8我就不多说了,21也是比较符合我们正常思路的6+7+8。
而在python,go,以及ruby中,没有自增运算符,这样也就大大减少了这种因版本和编译器的差异导致运行结果不同的概率。
C语言中不可告人的(i++)+(i++)+(i++)!!!你发现了吗?