首页 > 解决方案 > 这是使用 union vs reinterpret_cast 的合适案例吗

问题描述

我正在从 io 设备接收四个字(32 位)的数据。消息中的第一个词告诉我传入的数据是什么。我想知道这是否是使用 union 或 reinterpret_cast 的情况。

这是我的用例...

struct Plain {
  uint32_t  type;
  uint32_t data1;
  uint32_t data2;
  uint32_t data3;
}
struct Special1 {
  uint32_t  type;
  uint32_t data1;
  float    data2;
  uint32_t data3;
}

struct Special2 {
  uint32_t  type;
  uint32_t data1;
  float    data2;
  uint16_t data3;
  uint16_t data4;
}
union My_union {
  Plain    p1;
  Special1 p2;
  Special2 p3;

}
void foo(const Special1& x);
void foo(const Special2& x);
int main() {
  My_union x;
  read(&x.p1, sizeof(Plain)); // read from an IO device
  if(x.p1.type == 1)
  {
    foo(x.p2);
  }
  else
  {
    foo(x.p3);
  }
  return 0;
}

我试图弄清楚这是否是使用工会的合适案例,或者演员仍然是要走的路,如果是,为什么?

标签: c++unions

解决方案


如果对象x被正确初始化,则ifin 中的语句main() 将是合法的,因为尽管[class.union]/1C++ 标准的条款中有以下限制:

1)在联合中,如果一个非静态数据成员的名称引用了一个生命周期已经开始但尚未结束的对象,则它是活动的。union 类型的对象的非静态数据成员在任何时候最多可以有一个是活动的,即在任何时候最多可以将一个非静态数据成员的值存储在一个 union 中。

以下异常允许您访问公共成员type

一个特殊的保证是为了简化联合的使用:如果一个标准布局联合包含几个共享一个公共初始序列的标准布局结构,并且如果这个标准布局联合的对象的一个​​非静态数据成员type 是活动的并且是标准布局结构之一,它允许检查任何标准布局结构成员的公共初始序列。

但是您的代码段中的问题是您创建了一个联合对象x而不激活其任何成员([basic.life]/1.2):

(...) 如果对象是联合成员或其子对象,则它的生命周期仅在联合成员是联合中的初始化成员时才开始

这意味着当没有成员处于活动状态时,您直接将一些数据读入联合对象,因此仍然没有成员处于活动状态。严格遵循标准,我知道这根本不能保证有效。

正确的方法是读取type,然后初始化相关成员并在其中读取结构的其余部分(或将所有内容读入缓冲区并按照类似策略进行复制)。但是,实际上,您的代码将适用于大多数编译器。


推荐阅读