c++(vs上)与g++(linux下)对于++操作的汇编代码解读
先来看一个代码,估计很多同学都碰到过其中的某一个。
#include <stdio.h> #include <iostream> using namespace std; int main() { int a = 5; printf("a++ = %d\n", a++); a = 5; printf("++a = %d\n", ++a); a = 5; printf("a += a++ =%d\n", a += a++); a = 5; printf("a += (a++) =%d\n", a = a + (a++)); a = 5; printf("a += ++a =%d\n", a += ++a); a = 5; printf("a += (++a) =%d\n", a += (++a)); a = 5; printf("++a += a++ =%d\n", ++a += a++); a = 5; printf("(++a) += (a++) =%d\n", (++a) += (a++)); return 1; }
估计很多同学都饱受摧残(T-T)。
更坑的是,卧槽不同编译器下会有不用的结果。(╯°口°)╯(┴—┴
a.VS2013下的运行结果
b.g++下的运行结果
从结果可以看出,除了最开始两个书本上教的a++与++a是一致的(a++是先取a值然后再执行a=a+1,++a是先a = a+1,在取a的值)外,其他很多都不相同。
(゚Д゚≡゚д゚)!? 这也能玩?
百思不得其姐,打开汇编代码一探究竟。
先来看下vs下的汇编(拍下脑子想下大一学的汇编):
/* vs2013 */ 13: printf("a += a++ =%d\n", a += a++); 011ECAC7 mov eax,dword ptr [a] //把a的值放入eax寄存器中 011ECACA add eax,dword ptr [a] //把a的值加到eax中(eax = eax+a ) 011ECACD mov dword ptr [a],eax //把eax的值放入a, 以上就是 += 的操作 011ECAD0 mov ecx,dword ptr [a] //把a放入ecx寄存器中 011ECAD3 mov dword ptr [ebp-0D0h],ecx //直接打印了。。。--! 也就是忽略了a++ 直接打印了 011ECAD9 mov edx,dword ptr [a] //接下来就是执行a++,以及以下基础操作了。 011ECADC add edx,1 011ECADF mov dword ptr [a],edx 011ECAE2 mov esi,esp 011ECAE4 mov eax,dword ptr [ebp-0D0h] 011ECAEA push eax 011ECAEB push 11F832Ch 011ECAF0 call dword ptr ds:[11FC1E4h] 011ECAF6 add esp,8 011ECAF9 cmp esi,esp 011ECAFB call __RTC_CheckEsp (011E1631h)
简单的分析了,发现vs中a++的操作放在最后面执行。
再来瞧瞧g++的汇编代码:
g++下汇编和vs下汇编有很大不同,最大的一个是
vs: mov a,b 指将b->a
g++: mov a,b 指将a->b
(我改了下顺序,你就不能说我抄袭了吧 😄)
/* g++ 4.8.2 */ 13 printf("a += a++ =%d\n", a += a++); 0x08048602 <+85>: mov 0x1c(%esp),%eax //将这行代码的变量也就是a 给 eax寄存器, 0x08048606 <+89>: lea 0x1(%eax),%edx //表示将 eax里的值 + 1 赋值给 edx寄存器, 0x08048609 <+92>: mov %edx,0x1c(%esp) // edx -> a (此时a为6,eax为5) 0x0804860d <+96>: add %eax,0x1c(%esp) // a = a + eax 0x08048611 <+100>: mov 0x1c(%esp),%eax // 接下来就是调用打印的程序了 0x08048615 <+104>: mov %eax,0x4(%esp) 0x08048619 <+108>: movl $0x8048814,(%esp) 0x08048620 <+115>: call 0x80484a0 <printf@plt>
从汇编代码可以看出,g++编译时,把a++运算的a先放入一个寄存器eax,然后立马执行a = a+1,这时寄存器eax的值还是没有变的,然后再执行a = a+eax,所以结果为11.
通过汇编的理解,我们知道了机器到底是怎么做这些运算的,有兴趣的同学还可以把后面几个更复杂的式子用汇编代码敲敲,但是我选择以后编程的时候多加括号。(´・_・`)
如果要强行总结: 那么vs编译时把a++这种操作放在最后进行,所以在分析时先忽略这个操作,最后再来。 而g++ 则先把a拿到一个寄存器中准备以后用,然后立马执行a = a+1,真正用的时候还是用的寄存器里的值。