Xev*_*ous 0 c++ floating-point floating-point-conversion
如果我运行这段代码:
#include <iostream>
#include <cstdint>
int main()
{
double a = -2.0;
const double b = -2.0;
using std::cout;
cout << "Direct cast double -> uint16:\n";
cout << "a1: " << static_cast<std::uint16_t>(a) << "\n";
cout << "b1: " << static_cast<std::uint16_t>(b) << "\n";
auto a2 = static_cast<std::uint16_t>(a);
auto b2 = static_cast<std::uint16_t>(b);
cout << "a2: " << a2 << "\n";
cout << "b2: " << b2 << "\n";
cout << "Indirect cast double -> uint16:\n";
cout << "a3: " << static_cast<std::uint16_t>(static_cast<std::int16_t>(a)) << "\n";
cout << "b3: " << static_cast<std::uint16_t>(static_cast<std::int16_t>(b)) << "\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到以下结果:
海湾合作委员会x86-64:
Direct cast double -> uint16:
a1: 0
b1: 0
a2: 0
b2: 0
Indirect cast double -> uint16:
a3: 65534
b3: 65534
Run Code Online (Sandbox Code Playgroud)
铿锵 x86-64:
Direct cast double -> uint16:
a1: 540684641
b1: 540684642
a2: 540684897
b2: 540684898
Indirect cast double -> uint16:
a3: 65534
b3: 65534
Run Code Online (Sandbox Code Playgroud)
我的问题是:
a1
、b1
、a2
和b2
是 4 个不同的值。对我来说这看起来像是一个编译器错误,特别是考虑到以下事实2^16 = 65536
.a3
在and的情况下,中间类型的引入是否会改变语义(代码的含义)b3
?根据标准(https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf,第4.9节,\xc2\xa71),你会导致未定义的行为:
\n\n\n浮点类型的纯右值可以转换为整数类型的纯右值。转换截断;也就是说,小数部分被丢弃。如果截断值无法在目标类型中表示,则行为未定义。\n
\n
UB 意味着任何事情都可能发生,程序甚至可以输出无法用 UB 表示的值uint16_t
(例如540684641)。