c++ - 了解 MSVS C++ 编译器优化

标签 c++ c visual-studio optimization assembly

我不明白这段代码中发生了什么。 C代码是:

#include <stdio.h>

int main()
{
    const int mul = 100;
    int x;
    printf_s("Input a number\r\n");
    scanf_s("%i", &x);
    printf_s("%i/%i = %i\r\n", x, mul, x / mul);
    return 0;
}

我预计生成的程序集将是一些简单的移位和加/减操作,但有一些神奇的常量,如 51EB851Fh、乘法等。这里发生了什么?

; int __cdecl main()
_main proc near

x= dword ptr -8
var_4= dword ptr -4

push    ebp
mov     ebp, esp
sub     esp, 8
mov     eax, ___security_cookie
xor     eax, ebp
mov     [ebp+var_4], eax
push    offset Format   ; "Input a number\r\n"
call    ds:__imp__printf_s
lea     eax, [ebp+x]
push    eax
push    offset aI       ; "%i"
call    ds:__imp__scanf_s
mov     ecx, [ebp+x]
mov     eax, 51EB851Fh
imul    ecx
sar     edx, 5
mov     eax, edx
shr     eax, 1Fh
add     eax, edx
push    eax
push    64h
push    ecx
push    offset aIII     ; "%i/%i = %i\r\n"
call    ds:__imp__printf_s
mov     ecx, [ebp+var_4]
add     esp, 1Ch
xor     ecx, ebp        ; cookie
xor     eax, eax
call    @__security_check_cookie@4 ; __security_check_cookie(x)
mov     esp, ebp
pop     ebp
retn
_main endp

最佳答案

处理器不太擅长除法,一个 idiv 可能需要 11 到 18 个周期。与移位和乘法相反,它们通常只需要一个周期。

因此优化器使用定点数学乘法代替了您的除法,利用 32 位乘法将 64 位结果生成到 edx:eax。信封背面:n/100 == n * 0.32/32 == n * (0.32 * pow(2,32))/32/pow(2,32)。这些部门非常便宜,只是右移。乘数变为 0.32 * pow(2,32) ~= 1374389535 == 0x51EB851F

关于c++ - 了解 MSVS C++ 编译器优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24628899/

相关文章:

c++ - DLL 导出函数签名

c++ - getopt_long 不打印错误消息

将 const char* 复制到 char 数组中(面临错误)

c - fork 和 execve 段错误

c - 预测输出出错! - 使用 "fprintf & stdout"时这里发生了什么

visual-studio - 如何附加到 Visual Studio 中的进程?

c++ - 重新 -'new' TCHAR* 数组

c++ - 如何使用有限的 fork 数量运行类似 shell 的管道任务?

visual-studio - TFS、SVN 和 GIT 有什么区别?

asp.net-mvc - 如何在 IIS 中使用带有 https 的域名而不是 localhost 来调试网站