c++(vs上)与g++(linux下)对于++操作的汇编代码解读
2016-08-30 16:21
309 查看
先来看一个代码,估计很多同学都碰到过其中的某一个。
估计很多同学都饱受摧残(T-T)。
更坑的是,卧槽不同编译器下会有不用的结果。(╯°口°)╯(┴—┴
a.VS2013下的运行结果
b.g++下的运行结果
从结果可以看出,除了最开始两个书本上教的a++与++a是一致的(a++是先取a值然后再执行a=a+1,++a是先a=a+1,在取a的值)外,其他很多都不相同。
从汇编代码可以看出,g++编译时,把a++运算的a先放入一个寄存器eax,然后立马执行a=a+1,这时寄存器eax的值还是没有变的,然后再执行a=a+eax,所以结果为11.
通过汇编的理解,我们知道了机器到底是怎么做这些运算的,有兴趣的同学还可以把后面几个更复杂的式子用汇编代码敲敲,但是我选择以后编程的时候多加括号。(´・_・`)
如果要强行总结:那么vs编译时把a++这种操作放在最后进行,所以在分析时先忽略这个操作,最后再来。而g++则先把a拿到一个寄存器中准备以后用,然后立马执行a=a+1,真正用的时候还是用的寄存器里的值。
#include<stdio.h> #include<iostream> usingnamespacestd; intmain() { inta=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++)); return1; }
估计很多同学都饱受摧残(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++); 011ECAC7moveax,dwordptr[a] //把a的值放入eax寄存器中 011ECACAaddeax,dwordptr[a] //把a的值加到eax中(eax=eax+a) 011ECACDmovdwordptr[a],eax //把eax的值放入a,以上就是+=的操作 011ECAD0movecx,dwordptr[a] //把a放入ecx寄存器中 011ECAD3movdwordptr[ebp-0D0h],ecx//直接打印了。。。--!也就是忽略了a++直接打印了 011ECAD9movedx,dwordptr[a] //接下来就是执行a++,以及以下基础操作了。 011ECADCaddedx,1 011ECADFmovdwordptr[a],edx 011ECAE2movesi,esp 011ECAE4moveax,dwordptr[ebp-0D0h] 011ECAEApusheax 011ECAEBpush11F832Ch 011ECAF0calldwordptrds:[11FC1E4h] 011ECAF6addesp,8 011ECAF9cmpesi,esp 011ECAFBcall__RTC_CheckEsp(011E1631h)
简单的分析了,发现vs中a++的操作放在最后面执行。 再来瞧瞧g++的汇编代码: g++下汇编和vs下汇编有很大不同,最大的一个是 vs:mova,b指将b->a g++:mova,b指将a->b (我改了下顺序,你就不能说我抄袭了吧😄)
/*g++4.8.2*/ 13printf("a+=a++=%d\n",a+=a++); 0x08048602<+85>:mov0x1c(%esp),%eax //将这行代码的变量也就是a给eax寄存器, 0x08048606<+89>:lea0x1(%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>:mov0x1c(%esp),%eax //接下来就是调用打印的程序了 0x08048615<+104>:mov%eax,0x4(%esp) 0x08048619<+108>:movl$0x8048814,(%esp) 0x08048620<+115>:call0x80484a0<printf@plt>
从汇编代码可以看出,g++编译时,把a++运算的a先放入一个寄存器eax,然后立马执行a=a+1,这时寄存器eax的值还是没有变的,然后再执行a=a+eax,所以结果为11.
通过汇编的理解,我们知道了机器到底是怎么做这些运算的,有兴趣的同学还可以把后面几个更复杂的式子用汇编代码敲敲,但是我选择以后编程的时候多加括号。(´・_・`)
如果要强行总结:那么vs编译时把a++这种操作放在最后进行,所以在分析时先忽略这个操作,最后再来。而g++则先把a拿到一个寄存器中准备以后用,然后立马执行a=a+1,真正用的时候还是用的寄存器里的值。
相关文章推荐
- 在linux下用gdb调试gcc编译的代码;以及反汇编的操作
- 在Linux中使用VS Code编译调试C++项目(gcc/g++、Makefile入门、vs code)
- 基于LINUX平台G++编译器从汇编层面深度剖析C++虚函数
- Linuxg++编译C++代码出错 -std=c++11 or -std=gnu++11
- c++代码在windows,aix,linux上的移植
- 用c++ 操作mysql 数据库类(for linux or windows and others)
- Linux/Unix C/C++编程 Eclipse中代码格式化 (图)
- 如何在Linux下用C/C++语言操作数据库sqlite3
- 用c++ 操作mysql 数据库类(for linux or windows and others)
- 如何在Linux下用C/C++语言操作数据库sqlite3
- 操作系统中关于信号量操作的代码示例(Linux + windows)
- c++ 操作.ini 文件(适用平台linux windows)
- 在C++中内嵌汇编代码分析
- linux kernel arm 汇编代码部分的一点知识
- 这么详细的分类 VC/C++源代码网站你见过没有? VC/C++中的每一个方法,每一个操作,每一个头文件,每一个函数,每一个类.每一个属性,每一个事件都有相应的范例代码
- win32和Linux下的汇编代码框架
- [DLL]模仿C++中INI文件代码操作习惯的XML配置文件类
- TabBars代码解读之——C++文件切换功能
- C++中操作数据库的几段代码
- 解析C++汇编代码-局部变量空间分配及程序栈操作