在学习C的过程中发现了一件诡异的事情,在运行"++i"时两者的逻辑是一样的,但是在运行"++i + ++i"时就有问题了,如下图代码在java中输出为23,在C中输出为24.
伪代码:
int i=10;
int j=++i + ++i;
printf("%d",j);
java:
C:
明明是同一段代码,在java中输出的是23,但是C中却是24,怀着好奇我打开了两者的反汇编文件,研究了一会儿找到了问题所在
java:
java的.class文件在IDEA中打开是这样的,可以看到是在变量3运行之前,先给变量2自增一次,然后是"变量3=变量2++ +变量2"(这段代码在C里输出的是2*变量2),最后输出23,可以看出在java的公式中变量的值是动态变化的,每加载一个变量就变化一次。
javap:
在控制台输入"javap -c 文件名"可以打开.class文件的反汇编,进行分析
第11行:寄存器2存的是i的值
第12行:寄存器2自增
(中间少了两行)
第15行:寄存器2的值载入
第16行:寄存器2自增
可以看到公式计算过程中变量值确实是动态变化的,符合上面的猜想。
C:
这是C语言的反汇编,可以在vs:调试->窗口->反汇编 中打开,下面是分析:
00007FF7A3B55A0B mov dword ptr [i],0Ah //将0Ah(10)放入i的位置
00007FF7A3B55A12 mov eax,dword ptr [i] //将[i]放入eax寄存器
00007FF7A3B55A15 inc eax //eax寄存器自增
00007FF7A3B55A17 mov dword ptr [i],eax //将eax里的值放回[i]的位置
00007FF7A3B55A1A mov eax,dword ptr [i]
00007FF7A3B55A1D inc eax
00007FF7A3B55A1F mov dword ptr [i],eax
00007FF7A3B55A22 mov eax,dword ptr [i] //将[i]的值先放入eax寄存器
00007FF7A3B55A25 mov ecx,dword ptr [i] //再将[i]的值放入ecx寄存器
00007FF7A3B55A28 add ecx,eax //执行加法操作
00007FF7A3B55A2A mov eax,ecx //将ecx的值给eax,加法结果默认在第二个寄存器
00007FF7A3B55A2C mov dword ptr [k],eax //将值放入[k]的位置
可以看到在C中执行“k=++i + ++i”时,是先把公式中的所有有自增操作变量有进行一次自增,然后把值放入寄存器进行操作,在公式执行过程中是静态的,在公式执行前将所有需要的操作已经做完了。
其他还有很多自增自减的操作,感兴趣的可以去试一下,原理都是一样的。
总结:
在java中,公式是一步一步运行的,每运行一步就会更新变量的变化;
在C中,公式里的变量会在执行前将所有需要的操作执行完毕,然后执行公式,最后执行所有公式执行后需要的操作。