包含std::uint8_t与std::uint32_t数组的C++ union是否存在公共初始序列问题?
含两个std::array成员的联合体公共初始序列问题解析
你遇到的「GCC 10.1环境下代码可正常编译、跨成员读写结果符合预期、静态断言通过」的表现,和公共初始序列规则的合规性没有直接关联,具体拆解如下:
- 公共初始序列的规则边界
C++标准定义的公共初始序列(CIS)规则,仅允许联合体在合规场景下,读取与当前活跃成员属于同一公共初始序列的非静态数据成员。这套规则的比对对象,是联合体两个成员类型本身的逐对非静态数据成员,不会延伸到类模板内部封装的存储结构。 - 你定义的联合体不满足CIS适用条件的原因
你实现的联合体结构如下:
联合体的两个成员分别是元素类型为union MyUnion { static constexpr std::size_t size = 32; using byte = std::uint8_t; using word = std::uint32_t; std::array<byte, size> bytes; std::array<word, size / sizeof(word)> words; }; static_assert(sizeof(MyUnion)==32);std::uint8_t、长度32的std::array,以及元素类型为std::uint32_t、长度8的std::array。std::array作为标准布局聚合类型,它的实际连续字节存储是被封装在类内部的数组成员,两个不同元素类型、不同长度的std::array本身不存在任何公共的非静态成员,自然无法构成公共初始序列。也就是说,你切换活跃成员后跨字段读写的操作,在严格的C++标准层面属于未定义行为。 - GCC 10.1下无告警的原因
你使用的GCC 10.1版本,对这类通过联合体跨成员读取原始内存的写法,默认提供了兼容性扩展:只要不同成员的存储大小、内存对齐满足要求,编译器就会允许这类重解释操作,哪怕它不符合C++标准的严格约束。你观察到的静态断言通过、跨成员读写结果符合预期的表现,都是该扩展生效的结果,不是代码本身满足CIS合规要求的证明。 - 可移植的合规实现
如果需要在完全符合C标准的前提下实现同一块内存的跨类型字节访问,不需要依赖公共初始序列规则,也不需要绑定特定编译器的扩展,可以直接使用C20提供的std::bit_cast完成安全的内存重解释,相比联合体实现可移植性更强,也不会触发未定义行为。
内容的提问来源于stack exchange,提问作者Xpector
相关产品推荐
相关产品推荐

