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

Posted chenhuan001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 <[email protected]>

从汇编代码可以看出,g++编译时,把a++运算的a先放入一个寄存器eax,然后立马执行a = a+1,这时寄存器eax的值还是没有变的,然后再执行a = a+eax,所以结果为11.

 

通过汇编的理解,我们知道了机器到底是怎么做这些运算的,有兴趣的同学还可以把后面几个更复杂的式子用汇编代码敲敲,但是我选择以后编程的时候多加括号。(´?_?`)

如果要强行总结: 那么vs编译时把a++这种操作放在最后进行,所以在分析时先忽略这个操作,最后再来。 而g++ 则先把a拿到一个寄存器中准备以后用,然后立马执行a = a+1,真正用的时候还是用的寄存器里的值。

 

 

以上是关于c++(vs上)与g++(linux下)对于++操作的汇编代码解读的主要内容,如果未能解决你的问题,请参考以下文章

C++ VS17 给出的输出与 Linux 子系统中的相同代码不同

G++与VS2015在变量作用域上的差异性

VScode配置C++出现无法识别g++问题怎么办?

ubuntu(Linux)安装Vs code并配置c++编译及cmake多文件编译

Linux下C++静态库动态库的制作与使用

centos下怎么搭建c++的开发环境