C++ union 与 reinterpret_cast

标签 c++ unions reinterpret-cast

它出现在 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

最佳答案

未定义的原因是因为无法保证 intfloat 的值表示究竟是什么。 C++ 标准没有说 float 存储为 IEEE 754 单精度 float 。关于您将具有值 0xffffint 对象视为 float 的标准究竟应该怎么说?除了它是未定义的事实之外,它什么也没说。

然而,实际上,这是 reinterpret_cast 的目的 - 告诉编译器忽略它所知道的关于对象类型的所有内容,并相信你这个 int 实际上是 float 。它几乎总是用于特定于机器的位级跳棋。一旦你这样做了,C++ 标准就不能保证任何事情。到那时,您需要准确了解您的编译器和机器在这种情况下的作用。

unionreinterpret_cast 方法都是如此。我建议 reinterpret_cast 对这项任务“更好”,因为它使意图更清晰。但是,保持代码定义明确始终是最好的方法。

关于C++ union 与 reinterpret_cast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16637074/

相关文章:

c++ - 从保存在字符串 vector C++ 中的文本文件中检查单词序列

c++ - 在 C++ 中交换 void* 指针

C++ 访问 union 结构中的变量

c++ - 分配给已删除/未初始化的对象

c - 在 C 中获取 union 成员的地址是否合法?

c# - 等同于 C# 中 C++ 的 reinterpret_cast

c++ - 未指定的指针转换在 C++14 中的行为如何?

c++ - reinterpret_cast 使 constexpr 函数失败

c++ - 甚至没有声明的函数的 Unresolved external symbol 链接器错误?

c++ - Emacs 为每个连续的行缩进一个额外的级别