vc编译器对 除法的优化

基本知识,7/2 和 6/2 在计算机中的商都为3.C语言的除法不等同于数学意义中的除法。

C语言的除法。采用向零取整的方法。

-______________0_______________+

只有在除数为常量的情况下。编译器才会出现优化。

1、除数为正数,2的幂的除法

#include "stdafx.h"

int main(int argc, char* argv[])
{
  int iNum = argc;
  printf("%d\r\n", iNum / 2);
  printf("%d\r\n", iNum / 4);
  return 0;
}

对应Release版本的反汇编如下:

push    esi
mov     esi, dword ptr [esp+8]
mov     eax, esi
cdq
sub     eax, edx
sar     eax, 1
push    eax
push    test.00407030                    ;  ASCII "%d",CR,LF
call    test.00401040
mov     eax, esi
add     esp, 8
cdq
and     edx, 3
add     eax, edx
sar     eax, 2
push    eax
push    test.00407030                    ;  ASCII "%d",CR,LF
call    test.00401040
add     esp, 8
xor     eax, eax
pop     esi
retn

是不是感觉很奇怪,怎么没有了除法指令。查阅CPU手册。除法的指令周期数。大得吓人。具体值得根据cpu型号。翻阅 手册。

所以。编译器想尽办法。就是为了避免产生除法。提高效率。

 

mov     esi, dword ptr [esp+8]
mov     eax, esi
cdq
sub     eax, edx
sar     eax, 1

cdq 是把符号位扩展到 edx. 然后做加法。我们知道。对于被除数为正的情况,其值不变。除以2的幂。等于做 sar右移。

对于被除数为负的情况。那么由于sar右移。等同于向下取整。由于C语言是向零取整。所以。必须想办法下整转上整。就满足了C语言的向零取整。

于是公式来了。 a为被除数,n为2的幂.     (a + 2^n - 1)/2^n

对于 iNum / 2 那就是等于  (iNum + 2 - 1)/2 。常量折叠。等于(iNum + 1)/2。除以2等于sar右移一位。

那么就完美解决了除以2且无分歧的优化。指令的总周期。相对于div指令要减少很多。

在按照公式推导 iNum /4 的情况。(iNum + 2^2 - 1) / 2^2 。常量折叠。等于(iNum + 3) / 4。除以4等于sar右移两位。

对应的汇编代码如下。

mov     eax, esi
cdq
and     edx, 3
add     eax, edx
sar     eax, 2

推荐本书籍:《C++反汇编与逆向分析技术揭秘》。

国内第一家从事软件逆向工程师培训的机构。http://www.51asm.com 强烈推荐!

 

转载于:https://www.cnblogs.com/ziolo/p/3511488.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值