从 long double 到 unsigned long long 的转换在 MSVC C++ 中似乎已损坏。编译器
考虑以下代码:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
long double test = 0xFFFFFFFFFFFFFFFF;
cout << "1: " << test << endl;
unsigned long long test2 = test;
cout << "2: " << test2 << endl;
cout << "3: " << (unsigned long long)test << endl;
return 0;
}
使用 GCC g++ (7.5.0) 编译此代码并运行会按预期生成以下输出:
1: 1.84467e+19
2: 18446744073709551615
3: 18446744073709551615
但是,使用 Microsoft Visual C++ 编译器(16.8.31019.35,64 位和 32 位)编译此代码并运行产生以下输出:
1: 1.84467e+19
2: 9223372036854775808
3: 9223372036854775808
将值转换为 unsigned long long
时,MSVC 编译器不会给出大于(有符号)long 的最大值的值长
。
我做错了什么吗?
我是否遇到了我不知道的编译器限制?
有谁知道这个问题的可能解决方法?
Consider the following code:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
long double test = 0xFFFFFFFFFFFFFFFF;
cout << "1: " << test << endl;
unsigned long long test2 = test;
cout << "2: " << test2 << endl;
cout << "3: " << (unsigned long long)test << endl;
return 0;
}
Compiling this code with GCC g++ (7.5.0) and running produces the following output as expected:
1: 1.84467e+19
2: 18446744073709551615
3: 18446744073709551615
However compiling this with the Microsoft Visual C++ compiler (16.8.31019.35, both 64-bit and 32-bit) and running produces the following output:
1: 1.84467e+19
2: 9223372036854775808
3: 9223372036854775808
When casting a value to an unsigned long long
, the MSVC compiler won't give a value lager than the max of a (signed) long long
.
Am I doing something wrong?
Am I running into a compiler limitation that I do not know about?
Does anyone know of a possible workaround to this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为 MSVC
long double
实际上只是一个double
(正如@drescherjm 在评论中指出的那样),它没有足够的精度来包含 0xFFFFFFFFFFFFFFFF 的精确值。当此值存储在 long double 中时,它会“四舍五入”为大于 0xFFFFFFFFFFFFFFFF 的值。当转换为unsigned long long
时,这会导致未定义的行为。Because a MSVC
long double
is really just adouble
(as pointed out by @drescherjm in the comments), it does not have enough precision to contain the exact value of 0xFFFFFFFFFFFFFFFF. When this value is stored in thelong double
it gets "rounded" to a value that is lager than 0xFFFFFFFFFFFFFFFF. This then causes undefined behaviour when converting to anunsigned long long
.您看到未定义的行为,因为正如注释中所指出的,
long double
与 MSVC 中的double
以及的“转换”值相同0xFFFFFFFFFFFFFFFF
(或ULLONG_MAX
)实际上被“舍入”为一个稍大(但显着)的值,如以下代码所示:输出:
因此,当将该浮点值转换回
unsigned long long
时,您将违反 此 Microsoft 文档:通过切换到可在 Visual Studio 中使用的 clang-cl 编译器,可以进一步“验证”此 UB(因为需要一个更好的术语)。对于您的原始代码,这将为“2”和“3”输出行上的值提供
0
。假设 clang (LLVM) 编译器不受上述“微软规则”的约束,我们可以依靠 C++ 标准:
You are seeing undefined behaviour because, as pointed out in the comments, a
long double
is the same as adouble
in MSVC and the 'converted' value of your0xFFFFFFFFFFFFFFFF
(orULLONG_MAX
) actually gets 'rounded' to a slightly (but significantly) larger value, as can be seen in the following code:Output:
Thus, when converting that floating-point value back to an
unsigned long long
, you are falling foul of the conversion rules specified in this Microsoft document:This UB can be further 'verified' (for want of a better term) by switching to the clang-cl compiler that can be used from within Visual Studio. For your original code, this then gives
0
for the values on both the "2" and "3" output lines.Assuming that the clang (LLVM) compiler is not bound by the aforementioned "Microsoft Rules," we can, instead, fall back on the C++ Standard: