首页 > 代码库 > c++(vs上)与g++(linux下)对于++操作的汇编代码解读

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,真正用的时候还是用的寄存器里的值。

 

 

c++(vs上)与g++(linux下)对于++操作的汇编代码解读