Cha*_*429 3 c double type-conversion
我的代码如下:
int main(int argc, char *argv[])
{
double f = 18.40;
printf("%d\n", (int)(10 * f));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
VC6.0中的结果是184,而Codeblock的结果是183.为什么?
小智 8
原因是GCC试图尽可能地使代码向后兼容CPU的旧架构,而MSVC试图利用架构的新未来.
MSVC生成的代码将两个数字相乘,即10.0×18.40:
.text:00401006 fld ds:dbl_40D168
.text:0040100C fstp [ebp+var_8]
.text:0040100F fld ds:dbl_40D160
.text:00401015 fmul [ebp+var_8]
.text:00401018 call __ftol2_sse
Run Code Online (Sandbox Code Playgroud)
然后调用一个名为的函数__ftol2_sse,在这个函数中,它使用一些名为的指令将结果转换为整数cvttsd2si:
.text:00401189 push ebp
.text:0040118A mov ebp, esp
.text:0040118C sub esp, 8
.text:0040118F and esp, 0FFFFFFF8h
.text:00401192 fstp [esp+0Ch+var_C]
.text:00401195 cvttsd2si eax, [esp+0Ch+var_C]
.text:0040119A leave
.text:0040119B retn
Run Code Online (Sandbox Code Playgroud)
该指令cvttsd2si是根据此页面:
将标量双精度浮点值(带截断)转换为带符号的双字整数(SSE2)双字
它基本上将double转换为整数.该指令是Intel Pentium 4引入的名为SSE2的指令集的一部分.
GCC默认情况下不使用此指令集,并尝试使用i386中的可用指令进行操作:
fldl 0x28(%esp)
fldl 0x403070
fmulp %st,%st(1)
fnstcw 0x1e(%esp)
mov 0x1e(%esp),%ax
mov $0xc,%ah
mov %ax,0x1c(%esp)
fldcw 0x1c(%esp)
fistpl 0x18(%esp)
fldcw 0x1e(%esp)
mov 0x18(%esp),%eax
mov %eax,0x4(%esp)
movl $0x403068,(%esp)
call 0x401b44 <printf>
mov $0x0,%eax
Run Code Online (Sandbox Code Playgroud)
如果你想要使用GCC,cvttsd2si你需要通过编译标志告诉它使用SSE2提供的期货-msse2,但这也意味着仍然使用旧计算机的一些人将无法运行该程序.有关更多选项,请参阅此处Intel 386和AMD x86-64选项.
所以用-msse2它编译后会用到cvttsd2si将结果转换为32位整数:
0x004013ac <+32>: movsd 0x18(%esp),%xmm1
0x004013b2 <+38>: movsd 0x403070,%xmm0
0x004013ba <+46>: mulsd %xmm1,%xmm0
0x004013be <+50>: cvttsd2si %xmm0,%eax
0x004013c2 <+54>: mov %eax,0x4(%esp)
0x004013c6 <+58>: movl $0x403068,(%esp)
0x004013cd <+65>: call 0x401b30 <printf>
0x004013d2 <+70>: mov $0x0,%eax
Run Code Online (Sandbox Code Playgroud)
现在MSVC和GCC应该给出相同的数字:
> type test.c
#include <stdio.h>
int main(int argc, char *argv[])
{
double f = 18.40;
printf("%d\n", (int) (10.0 * f));
return 0;
}
> gcc -Wall test.c -o gcctest.exe -msse2
> cl test.c /W3 /link /out:msvctest.exe
> gcctest.exe
184
> msvctest.exe
184
>
Run Code Online (Sandbox Code Playgroud)