如何在C++中正确使用union?

How to use union in C++ correctly?

我在 C++ 中有以下联合

union MsgData {
      struct
      {
        uint32_t msb : 1;
        uint32_t reg_addr : 7;
        uint32_t data : 8;
        uint32_t fill : 3;
        uint32_t crc : 5;
      } bits;
      uint8_t bytes[3];
    };

如果我执行以下操作(address 包含 26data 包含 255 - 均为十进制):

  msg.bits.msb = 1;
  msg.bits.reg_addr = (address & 0x7F);
  msg.bits.data = data;
  msg.bits.fill = 0;
  msg.bits.crc = 0;

联合 MsgData 中的字节数组 bytes 包含:

msg.bytes[0]: 53
msg.bytes[1]: 255
msg.bytes[2]: 0

我期望 msg.bytes[0] 中的值为 154。谁能给我一个建议,为什么我在 msg.bytes[0] 中得到 53 而不是 154 值?

你的程序的行为是未定义的,因为你从联合会的一个不活跃的成员那里读取。

How to use union in C++ correctly?

总的来说:仅从最后分配的联合的活动成员读取。确实存在例外。例如,也允许从与活动成员具有相同类型的非活动成员读取。没有适用于您的程序的此类例外情况。

既然你想把类型双关成字节数组,还有另一种定义明确的方式:reinterpret_cast:

struct
{
    ...
} bits;

static_assert(std::is_same_v<uint8_t, unsigned char>);
uint8_t* bytes = reinterpret_cast<uint8_t*>(&bits);

请注意,通过此 bytes 指针进行读取是特别允许的,因为 unsigned char(以及其他一些类型)很特殊。


现在,假设您使用定义联合类型双关行为的语言扩展或使用上面显示的 reinterpret_cast

Can anybody give me an advice why I have got 53 instead of 154 value in the msg.bytes[0]?

因为这个:

reg_addr | msb | bit field
7654321  | 0   | bit index in order of significance
0011010  | 1   | bit value

0b00110101 == 53

不清楚您为什么会有其他预期。依赖位字段的顺序是不可移植的。