C语言中通过不透明指针访问结构体首成员的严格别名与未定义行为问询
分析ISO C代码中的未定义行为
struct S { int a; }; void f() { struct S s; *(int*)&s = 1; // 1 ((struct S*)(struct Opaque*)&s)->a = 2; // 2 *(int*)(struct Opaque*)&s = 3; // 3 }
已知结论确认
- 语句1无未定义行为:依据C17 §6.7.2.15规定,指向结构体对象的指针经适当转换后可指向其初始成员,反之亦然。这里将指向
struct S的&s转换为int*,实际指向s的首成员a,赋值操作合法。 - 语句2无未定义行为:尽管中间经过
struct Opaque*的强制转换,但最终是通过struct S*类型访问对象s,符合对象的有效类型,未违反严格别名规则(C17 §6.5.7)。
语句3的未定义行为判定
语句3存在未定义行为,核心原因如下:
- 非法的指针转换:C17 §6.7.2.15的转换规则仅适用于结构体指针与其首成员指针之间的转换,而
struct Opaque是未定义类型,无法保证它的内存布局与struct S兼容,也无法确认其首成员为int类型。将&s转换为struct Opaque*本身就不符合标准规定的合法转换场景。 - 违反严格别名规则:对象
s的有效类型是struct S,语句3最终通过int*类型访问该对象。根据严格别名规则(C17 §6.5.7),允许的访问类型仅包括对象的有效类型、兼容类型、有效类型的有符号/无符号变体、字符类型等,int与struct S不属于上述任何兼容范畴。即便中间经过struct Opaque*的转换,最终的访问方式依然违反了规则。
内容的提问来源于stack exchange,提问作者Etienne Dechamps
相关产品推荐
相关产品推荐

