快速简单的问题; 这个
typedef struct {int a; int b;} S1;
typedef struct {int a;} S2;
((S2*)(POINTER_TO_AN_S1))->a=1;
始终返回(并分配)结构的成员a?还是未定义的行为?
答案 0 :(得分:0)
在符合标准的编译器中,如果两个结构类型都出现在联合类型的完整定义中,该类型在访问结构时是可见的,并且如果指针的目标碰巧是该联合类型的实例,则行为将是定义。请注意,标准不要求编译器有任何方式知道指针的目标实际上是该联合类型的对象 - 仅仅是完整联合类型的声明是可见的。
但请注意,除非使用-fno-strict-aliasing
标志,否则gcc不遵守此处的标准。即使在完整联合类型可见的情况下,并且编译器可以看到它实际上使用了联合类型的对象,gcc也会忽略别名。例如,给定:
struct s1 {int x;};
struct s2 {int x;};
union u { struct s1 s1; struct s2 s2;};
int read_s1_x(struct s1 *p) { return p->x; }
int read_s2_x(struct s2 *p) { return p->x; }
int write_s1_x(struct s1 *p, int value) { p->x = value; }
int write_s2_x(struct s2 *p, int value) { p->x = value; }
int test(union u *u1, union u *u2)
{
write_s2_x(&u2->s2, 0);
if (!read_s1_x(&u1->s1))
write_s2_x(&u2->s2, 1);
return read_s1_x(&u1->s1);
}
编译器将决定它不需要重新读取其值 u1-> s1.x在写入u2-> s2.x之后,即使是完整的联合类型 是可见的,即使编译器可以看到u1和u2都是 指向union类型的对象的指针。我不太清楚是什么 gcc的作者认为运营商的地址应该意味着什么时候 如果生成的指针甚至不能用于,则应用于联合类型 立即访问该成员类型的对象。