C 中的结构扩展

fed*_*evi 3 c struct pointers compilation

假设定义了 2 个结构体,如下所示:

typedef struct {
   T x;
   T y;
} A;

typedef struct {
   A a;
   T z;
} B;
Run Code Online (Sandbox Code Playgroud)

我可以将指向结构 B 的指针视为指向结构 A 的指针吗?

实际上,这是可靠的/标准的/可移植的/编译器不变的:

B b = {{1,2},3};
A * a = &b;

print(a->x);
print(a->y);
Run Code Online (Sandbox Code Playgroud)

Lun*_*din 5

C17 6.7.2.1 指出了这一点(强调我的):

在结构体对象中,非位域成员和位域所在的单元的地址按照它们声明的顺序递增。指向结构对象的指针经过适当转换后,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然

这意味着您必须将对象的指针“适当地转换”B b为其第一个成员的类型。此转换不会隐式发生,您必须通过显式强制转换来完成此操作:

A * a = (A*)&b;
Run Code Online (Sandbox Code Playgroud)

根据上面引用的部分,这样做是明确定义且安全的。

同样,编译器不允许假设指向的指针A和指向的指针B没有别名。有效类型 6.5.7 的规则(“严格别名”)给出了这种情况的例外:

对象的存储值只能由具有以下类型之一的左值表达式访问:
...

  • 其成员中包含上述类型之一的聚合或联合类型

例如,在优化期间,void func (B* b)不允许调用该函数的编译器假设该函数extern A a;未更改某些其他翻译单元中定义的外部行数变量。

  • 顺便说一句,这就是您通常在 C 中实现 OO 继承的方式。如果“A”包含函数指针,则任何以“A”作为第一个成员的结构都可能会覆盖该函数指针以实现多态性,其中“a->func()” ;` 将调用继承的方法。 (3认同)