当前位置 : 主页 > 编程语言 > c++ >

C联盟成员访问和未定义的行为

来源:互联网 收集:自由互联 发布时间:2021-06-23
我目前正在开展一个项目,其中提供了以下内容 结构法.我的工作是C,但该项目同时使用C和C.结构相同 定义由C和C使用. typedef struct PacketHeader { //Byte 0 uint8_t bRes :4; uint8_t bEmpty :1; uint8_t bWa
我目前正在开展一个项目,其中提供了以下内容
结构法.我的工作是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;

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

//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)为成员wMake和赋值
wMod显式,并且不写入成员wId.我的问题是关于
从返回的实例中的成员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中访问一个非活动成员所引起的未定义行为.

链接草案第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]

正在读取packetIdFlipped = myHeader.wId<<行中的myHeader.wId 8未定义的行为? 未命名的结构是活动成员,因为它是函数调用中写入的最后一个成员吗? 或者注释是否意味着访问wId成员是安全的,因为它和struct共享一个共同的类型? (这是普通初始序列的意思吗?) 提前致谢

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来避免这种情况(参见this和this).

网友评论