它出现在 other StackOverflow questions并阅读 ISO/IEC draft C++ standard 的§9.5.1使用 union 做文字的标准reinterpret_cast
的数据是未定义的行为。
考虑下面的代码。目标是取 0xffff
的整数值并将其解释为 IEEE 754 浮点中的一系列位。 (Binary convert shows visually how this is done.)
#include <iostream>
using namespace std;
union unionType {
int myInt;
float myFloat;
};
int main() {
int i = 0xffff;
unionType u;
u.myInt = i;
cout << "size of int " << sizeof(int) << endl;
cout << "size of float " << sizeof(float) << endl;
cout << "myInt " << u.myInt << endl;
cout << "myFloat " << u.myFloat << endl;
float theFloat = *reinterpret_cast<float*>(&i);
cout << "theFloat " << theFloat << endl;
return 0;
}
此代码的输出是预期的,同时使用 GCC 和 clang 编译器。
size of int 4
size of float 4
myInt 65535
myFloat 9.18341e-41
theFloat 9.18341e-41
我的问题是,标准是否真的排除了 myFloat
的值?从确定性?是使用一个reinterpret_cast
以任何方式更好地执行这种类型的转换?
该标准在 §9.5.1 中规定了以下内容:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [...] The size of a union is sufficient to contain the largest of its non-static data members. Each non-static data member is allocated as if it were the sole member of a struct. All non-static data members of a union object have the same address.
最后一句话,保证所有非静态成员具有相同的地址,似乎表明 union 的使用保证与reinterpret_cast
的使用相同,但之前关于事件数据成员的声明似乎排除了这种保证。
那么哪个结构更正确?
编辑:
使用英特尔的 icpc
编译器,上面的代码会产生更有趣的结果:
$ icpc union.cpp
$ ./a.out
size of int 4
size of float 4
myInt 65535
myFloat 0
theFloat 0
最佳答案
未定义的原因是因为无法保证 int
和 float
的值表示究竟是什么。 C++ 标准没有说 float
存储为 IEEE 754 单精度 float 。关于您将具有值 0xffff
的 int
对象视为 float
的标准究竟应该怎么说?除了它是未定义的事实之外,它什么也没说。
然而,实际上,这是 reinterpret_cast
的目的 - 告诉编译器忽略它所知道的关于对象类型的所有内容,并相信你这个 int
实际上是 float
。它几乎总是用于特定于机器的位级跳棋。一旦你这样做了,C++ 标准就不能保证任何事情。到那时,您需要准确了解您的编译器和机器在这种情况下的作用。
union
和 reinterpret_cast
方法都是如此。我建议 reinterpret_cast
对这项任务“更好”,因为它使意图更清晰。但是,保持代码定义明确始终是最好的方法。
关于C++ union 与 reinterpret_cast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16637074/