这主要是对this other question的跟进,这是关于奇怪的从长到双的转换,然后再转回到长值的大值。
我已经知道将float转换为整数类型会截断,如果截断的值无法在目标类型中表示,则行为是未定义的:
4.9浮动积分转换[conv.fpint]
浮点类型的prvalue可以转换为整数类型的prvalue。转换截断; 也就是说,丢弃小数部分。如果截断值不能,则行为未定义 以目的地类型表示。
但是这是我的代码来演示这个问题,假设有一个小的endian架构,其中long long和long double都使用64位:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
unsigned long long ull = 0xf000000000000000;
long double d = static_cast<long double>(ull);
// dump the IEE-754 number for a little endian system
unsigned char * pt = reinterpret_cast<unsigned char *>(&d);
for (int i = sizeof(d) -1; i>= 0; i--) {
cout << hex << setw(2) << setfill('0') << static_cast<unsigned int>(pt[i]);
}
cout << endl;
unsigned long long ull2 = static_cast<unsigned long long>(d);
cout << ull << endl << d << endl << ull2 << endl;
return 0;
}
输出是(在旧的XP 32盒子上使用MSVC 2008 32位):
43ee000000000000
f000000000000000
1.72938e+019
8000000000000000
价值解释:
1
后跟0
- 指数是43e,在移除3ff偏差后它给出了1.111 2 63 因此确切表示0xf000000000000000或17293822569102704640(ref)由于该值可以表示为无符号长long,我预计它转换为无符号long long给出原始值,MSVC给出0x8000000000000000或9223372036854775808
问题是:是否由未定义的行为引起的转换是由另一个问题的接受答案所建议的,还是它真的是一个MSVC错误?
(注意:在FreeBSD 10.1框上的CLang编译器上的相同代码可以得到正确的结果)
对于参考,我可以找到生成的代码:
unsigned long long ull2 = static_cast<unsigned long long>(d);
0041159E fld qword ptr [d]
004115A1 call @ILT+490(__ftol2) (4111EFh)
004115A6 mov dword ptr [ull2],eax
004115A9 mov dword ptr [ebp-40h],edx
_ftol2的代码似乎是(在执行时从调试器获得):
00411C66 push ebp
00411C67 mov ebp,esp
00411C69 sub esp,20h
00411C6C and esp,0FFFFFFF0h
00411C6F fld st(0)
00411C71 fst dword ptr [esp+18h]
00411C75 fistp qword ptr [esp+10h]
00411C79 fild qword ptr [esp+10h]
00411C7D mov edx,dword ptr [esp+18h]
00411C81 mov eax,dword ptr [esp+10h]
00411C85 test eax,eax
00411C87 je integer_QnaN_or_zero (411CC5h)
00411C89 fsubp st(1),st
00411C8B test edx,edx
00411C8D jns positive (411CADh)
00411C8F fstp dword ptr [esp]
00411C92 mov ecx,dword ptr [esp]
00411C95 xor ecx,80000000h
00411C9B add ecx,7FFFFFFFh
00411CA1 adc eax,0
00411CA4 mov edx,dword ptr [esp+14h]
00411CA8 adc edx,0
00411CAB jmp localexit (411CD9h)
00411CAD fstp dword ptr [esp]
00411CB0 mov ecx,dword ptr [esp]
00411CB3 add ecx,7FFFFFFFh
00411CB9 sbb eax,0
00411CBC mov edx,dword ptr [esp+14h]
00411CC0 sbb edx,0
00411CC3 jmp localexit (411CD9h)
00411CC5 mov edx,dword ptr [esp+14h]
00411CC9 test edx,7FFFFFFFh
00411CCF jne arg_is_not_integer_QnaN (411C89h)
00411CD1 fstp dword ptr [esp+18h]
00411CD5 fstp dword ptr [esp+18h]
00411CD9 leave
00411CDA ret
答案 0 :(得分:1)
这主要是对问题的评论汇编。
旧的MSVC版本似乎错误地将64位整数的转换处理为64位双精度数。
2008年以下版本中存在的错误。
MSCV 2010在使用32位模式时出错并在64位模式下正确
从2012年开始的所有版本都是正确的。