C语言中两种结构体指针访问写法是否违反严格别名规则?
两种写法是否违反C语言严格别名规则?
先明确C语言严格别名规则的核心:一个对象只能通过与其兼容的类型指针、void*、char/unsigned char类型指针,或者符合特定例外的指针来访问,否则会违反规则,可能导致未定义行为。
第一种写法:违反严格别名规则
typedef struct{ int type; }foo_t; foo_t *foo = foo_init(); *(int*)foo = 1;
这里将foo_t*强制转换为int*后解引用赋值,相当于把类型为foo_t的对象当成int类型对象来访问。foo_t和int属于完全不兼容的类型,也不在严格别名规则允许的例外范围内,因此这种写法违反了严格别名规则,编译器可能会做出优化导致程序行为异常。
第二种写法:不违反严格别名规则
typedef struct{ int type; }bar_t; typedef struct{ bar_t header; }foo_t; foo_t *foo = foo_init(); ((bar_t*)foo)->type = 1;
C标准明确规定:指向结构体对象的指针可以转换为指向其第一个成员的指针,反之亦然,且两者的地址完全相同。这里bar_t是foo_t的第一个成员,所以把foo_t*转成bar_t*是合法的,后续通过bar_t*访问其type成员,本质是访问foo_t对象的第一个成员,完全符合严格别名规则的例外情况,因此这种写法不违反规则。
第二种写法更常见的原因
第二种写法之所以普及,核心是它合法规避了严格别名问题,同时这种“结构体嵌套头部”的写法是C语言中实现多态风格(类似面向对象的基类继承)的常用手段——通过统一的头部结构体标识对象类型,方便后续的类型判断和转换,不仅语法清晰,更重要的是符合标准规范,不会触发未定义行为。
内容的提问来源于stack exchange,提问作者Edwin Skeevers
相关产品推荐
相关产品推荐

