C/C++中读写联合不同类型成员的未定义行为差异问询
联合跨成员访问的未定义行为分析
我们直接从示例代码开始:
#include <stdio.h> #include <stdbool.h> typedef union { bool b; int i; } boolIntUnion; int main(void) { boolIntUnion val; val.i = 0; printf("i = %d; %s\n", val.i, ((val.b)? "true" : "false")); val.i = 1; printf("i = %d; %s\n", val.i, ((val.b)? "true" : "false")); val.i = 2; printf("i = %d; %s\n", val.i, ((val.b)? "true" : "false")); }
核心结论:该用法属于未定义行为
无论是C还是C++标准,这种联合跨成员访问的行为都被归类为未定义行为,具体依据如下:
C标准视角
根据C17标准§6.5.2.3第3款,当访问联合的某一成员时,若最后一次写入的是另一个成员,仅当两个成员类型兼容、或为指向兼容类型的指针、或其中一个是指向字符类型的指针时,访问行为才合法。
此处bool与int既不兼容,也不符合例外条件,因此整个跨成员访问的行为属于未定义行为。编译器可自由选择处理逻辑:
- GCC和MSVC选择将
int的整体非零性作为bool的真值判断依据,因此i=2时b返回true; - Clang则严格读取
bool成员对应的内存字节(通常为1字节),小端系统下i=2的最低字节值为0,因此b返回false。两种实现均符合标准对未定义行为的允许范围。
C++标准视角
C20标准§11.4.10第1款规定,联合中只有最后写入的成员为"活跃成员",访问非活跃成员的行为属于未定义行为,除非成员满足特定的类型兼容条件(如共用初始序列),而bool与int并不满足该条件。因此**在C中该代码同样属于未定义行为**。
建议
若需要确定的行为,应避免联合跨成员访问,改用显式转换逻辑,例如:
val.b = (val.i != 0);
内容的提问来源于stack exchange,提问作者0xLeon
相关产品推荐
相关产品推荐

