从汇编角度浅谈i++和++i的区别

从汇编角度浅谈i++和++i的区别

初学之时,我认为i++和++i其实并没有多大区别,i++是先取i的值,再给i值加1,++i是先给i值加1,再取i的值,都是自增运算,效率感觉都差不多,最终实现的都是i值加1。直到看到了下面的代码,我才发现i++和++i还是有很大差别的,尤其是在效率上。

这里写图片描述

当看到这道题时,我感觉挺简单的呀。首先,由于逗号运算符是从右往左进行,所以先打印最右边i++,再打印–i,最后打印最左边i++,自然而然结果为0 0 0,但是实际呢?

请看下面的结果 :
这里写图片描述

为什么和我想的不一样?我进入底层,看了反汇编代码才明白了是什么情况。那现在就让我来和大家聊聊反汇编代码吧。首先,请大家看一段反汇编代码。

这里写图片描述

上面的这一段长代码就是解决这个问题的答案,让我为大家一步步解析这段代码。

这里写图片描述

上面的代码就是创建一个i变量,然后将0放在i中。

这里写图片描述

代码逐行解析 :

第二行 : 将i的值(0)传入名为eax寄存器中;
第三行 : 创建一个地址为ebp-0E0h临时量,然后将eax中的值(0)传入这个临时量中;
第四行 : 将i的值(0)传入名为ecx寄存器中;
第五行 : 对ecx中的值(0)执行+1操作;
第六行 : 将ecx中的值(1)重新传回i中;
以上就是printf中括号最右边的i++操作。

第七行 : 将i的值(1)传入edx寄存器中;
第八行 : 对edx中的值(1)执行-1操作;
第九行 : 将edx中的值(0)重新传回i中;
以上就是括号中间的–i操作;

第十行 : 将i中的值(0)放在eax寄存器中;
第十一行 : 创建一个地址名为ebp-0E4h临时量,然后把eax中的值(0)传入这个临时量中;
第十二行 : 将i中的值(0)传入ecx寄存器中;
第十二行 : 对ecx中的值(0)执行+1操作;
第十三行 : 将ecx中的值(1)重新传回i中;
以上就是括号最左边的i++操作;

从以上的过程中,我们可以看出,两个i++操作将值分别传入ebp-0E0h,ebp-0E4h两个临时量中,再传入寄存器中进行++操作,而–i操作是将值直接放在寄存器中进行–操作,再将值传回i,不需要将值传入临时量中。此时,两个临时量所保存的值都是0,而i中的值为1。

接下来我们来看压参操作 :

这里写图片描述

第一行 : 将临时量ebp-0E0h中的值(0)传入edx寄存器中;
第二行 : 把edx中的值(0)压入栈中;
第三行 : 将i中的值(1)传入eax寄存器中;
第四行 : 把edx中的值(1)压入栈中;
第五行 : 将临时量ebp-0E4h中的值(0)传入ecx寄存器中;
第六行 : 把ecx中的值(0)压入栈中;

根据栈先进后出的原理,打印出来的值就是 0 1 0;
从压栈操作我们可以看出函数压栈并不是读到一个参数就往栈里压一个参数,而是先遍历一下,然后统一将参数压入栈中。
所以,我们可以得出执行i++操作时,会生成一个临时量来保存当前的值,但是执行–i时却直接执行了自减操作。这是由于CPU中寄存器的数量有限,不可能无限制去使用,所以生成临时量来保存值。

i++和++i的总结 :

执行后置++(–)操作,程序会自动生成临时量,然后将临时量的值进行压参,而执行前置++(–)操作,会直接运算,然后直到所有参数都读取完之后,再进行压参。因此,从汇编角度得出的结论是,由于前置运算不用产生临时量,所以使用前置++(–)的效率要比后置++(–)效率高。

猜你喜欢

转载自blog.csdn.net/xzg_2017/article/details/78347778
今日推荐