C++ union 成员访问和未定义行为

标签 c++ language-lawyer undefined-behavior unions

我目前正在从事一个项目,其中提供了以下内容 结构。我的工作是 C++,但该项目同时使用 C 和 C++。结构相同 定义被 C 和 C++ 使用。

typedef struct PacketHeader {
    //Byte 0
    uint8_t  bRes                           :4;
    uint8_t  bEmpty                         :1;
    uint8_t  bWait                          :1;
    uint8_t  bErr                           :1;
    uint8_t  bEnable                        :1;
    //Byte 1
    uint8_t  bInst                          :4;
    uint8_t  bCount                         :3;
    uint8_t  bRres                          :1;
    //Bytes 2, 3
    union {
        uint16_t wId;    /* Needed for Endian swapping */
        struct{
            uint16_t wMake                  :4;
            uint16_t wMod                   :12;
        };
    };
} PacketHeader;

根据结构实例的使用方式,所需的字节顺序 该结构可以是大端或小端。作为前两个字节 结构都是单个字节,这些在字节序时不需要改变 变化。 字节 2 和 3,存储为单个 uint16_t , 是我们唯一需要的字节 交换以实现所需的字节顺序。为了实现字节顺序交换,我们有 一直在执行以下操作:

//Returns a constructed instance of PacketHeader with relevant fields set and the provided counter value
PacketHeader myHeader = mmt::BuildPacketHeader(count);

uint16_t packetIdFlipped;
//Swap positions of byte 2 and 3
packetIdFlipped = myHeader.wId << 8;
packetIdFlipped |= (uint16_t)myHeader.wId >> 8;

myHeader.wId = packetIdFlipped;

函数BuildPacketHeader(uint8_t)为成员赋值 wMakewMod明确地,并且写给成员wId .我的问题是关于 成员(member)阅读安全wId在返回的实例中 结构。

诸如此类的问题 Accessing inactive union member and undefined behavior? , Purpose of Unions in C and C++ , 和 Section 10.4 of the draft standard I have每个人都提到了访问 C++ union 的非事件成员所引起的未定义行为。

链接草案第 10.4 节的第 1 段还包含以下说明,但我不确定我是否理解所有使用的术语:

[Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (10.3), and if a non-static datamember of an object of this standard-layout union type is active and is one of the standard-layout structs, itis permitted to inspect the common initial sequence of any of the standard-layout struct members; see 10.3.— end note]

正在阅读myHeader.wIdpacketIdFlipped = myHeader.wId << 8 行中未定义的行为?

未命名的结构是否是事件成员,因为它是函数调用中写入的最后一个成员?

或者注释是否意味着访问 wId 是安全的?成员,因为它和结构共享一个共同的类型? (这就是通用初始序列的意思吗?)

提前致谢

最佳答案

The function BuildPacketHeader(uint8_t) assigns values to the members wMake and wMod explicitly, and does not write to the member wId. My question is regarding the safety of reading from the member wId inside the returned instance of the structure.

是的,它是 UB。这并不意味着它不起作用,只是它可能不起作用。您可以在 BuildPacketHeader 中使用 memcpy 来避免这种情况(参见 thisthis)。

关于C++ union 成员访问和未定义行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55281667/

相关文章:

c++ - 如何在 directx 对象上使用 win32 C++ 获取鼠标单击的 x,y 坐标?

c++ - 对构造函数调用的约束

c - 为什么我可以在 gcc -std=c11 中使用 gets()?

c - 与严格别名相关的有效类型规则

c++ - 诸如 bits/vector.tcc 之类的头文件名是否符合标准?

c - 局部变量前的 GOTO

c++ - 这可以用静态类型来完成吗?

c++ - accept() 函数充当非阻塞

c - 为什么这些构造使用增量前和增量后未定义的行为?

c++ - 在 C++20 之前将 malloc 用于 int 未定义行为