将double转换为int?
我的代码如下:
int main(int argc,char *argv[]) { double f = 18.40; printf("%dn",(int)(10 * f)); return 0; } VC6.0中的结果为184,而Codeblock的结果为183.为什么? 解决方法
原因是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 然后调用一个名为__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 这条指令cvttsd2si是根据这个page:
它基本上将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 如果你想让GCC使用cvttsd2si,你需要通过使用标志-msse2编译来告诉它使用SSE2提供的期货,但这也意味着仍然使用旧计算机的一些人将无法运行该程序.有关更多选项,请参见此处Intel 386 and AMD x86-64 Options. 因此在使用-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 现在MSVC和GCC应该给出相同的数字: > type test.c #include <stdio.h> int main(int argc,(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 > (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |