我目前正在处理一个项目,其中提供了以下结构。我的工作是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
的第二个和第三个字节是我们需要交换以实现所需字节序的唯一字节。为了进行字节序交换,我们一直在执行以下操作:
//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++和我拥有的草案标准的第10.4节中都提到了在C++中访问联合的非活动成员时产生的未定义行为。
链接草案的第10.4节第1段还包含以下说明,尽管我无法理解使用的所有术语:
在[注意:为了简化联合的使用,作出了一个特殊的保证:如果标准布局联合包含多个共享公共初始序列(10.3)的标准布局结构体,并且此标准布局联合类型的对象的非静态数据 成员处于活动状态并且是其中一个标准布局结构,则允许检查任何标准布局结构成员的公共初始序列。参见10.3。 - 结束注意]
packetIdFlipped = myHeader.wId << 8
行中读取myHeader.wId
是否未定义行为?无名结构体是否是活动成员,因为它是函数调用中最后一个编写的成员?
还是说明意味着访问
wId
成员是安全的,因为它和结构体共享通用类型?(这是公共初始序列所指的吗?)提前感谢您。
struct{ /* 成员 */ };
- eerorikastruct PacketHeader
的成员? - cprlkleg