C语言Strict Aliasing与共用体:下述程序是否存在未定义行为?
C17标准下该程序的未定义行为分析
程序代码
#include <stdio.h> short g(int *p, short *q) { short z = *q; *p = 10; return z; } int main(void) { union int_or_short { int x; short y; } u = { .y = 3 }; int *p = &u.x; short *q = &u.y; short r = g(p, q); printf("%hd %d\n", r, u.x); }
结论:存在未定义行为
依据C17标准条款的分析
1. 严格别名规则(C17 §6.5/7)
C17明确规定:对象的值只能通过以下类型的左值访问:
- 对象的有效类型(即最近一次写入该对象时使用的类型);
- 与有效类型兼容的有符号/无符号对应类型;
- 与有效类型兼容的字符类型;
- 包含上述类型的聚合/联合类型;
- 指向上述类型的指针(用于访问子对象)。
在这个程序里:
- 初始化时通过
.y(short类型)给联合u赋值,此时u的有效类型是short。 - 函数
g中,先通过short*类型的q读取*q(即u.y),这符合规则,因为访问类型与有效类型一致。 - 但紧接着通过
int*类型的p执行*p = 10(修改u.x),此时u的有效类型还是short,而int和short既不兼容,也不属于规则允许的例外类型,直接违反了严格别名规则,触发未定义行为。
2. 联合成员访问规则(C17 §6.5.2.3/3)
C17对联合的访问补充规定:如果访问联合的成员类型,与最近一次写入联合的成员类型不兼容,且不符合严格别名规则的例外情况,行为未定义。
这里写入u.x(int类型)时,最近一次写入的是u.y(short类型),两者类型不兼容,也不满足例外条件,进一步确认了未定义行为的存在。
补充说明
联合的所有成员共享同一块内存,&u.x和&u.y指向同一地址,但指针类型不同。通过不同类型的指针跨类型修改对象,正是严格别名规则要限制的场景——这种操作会让编译器的优化假设失效,可能导致不可预测的执行结果(比如编译器可能优化掉读取*q的操作,或生成不符合预期的内存访问指令)。
内容的提问来源于stack exchange,提问作者Steve Siegel
相关产品推荐
相关产品推荐

