C中的"动态继承"

Jon*_*ger 2 c oop struct pointers

我编写了以下代码并且它可以工作,但我想知道是否可以确保它在所有x86机器上始终有效.

#include <stdio.h>
#include <stdlib.h>

typedef struct Base {
  int a;
  float b;
} Base;

typedef struct Derived1 {
  int a;      // This two members have the same position as in the Base
  float b;

  // adding some other members to this struct
  int otherMember;
  int otherMember2;
} Derived1;

int main()
{
  Base *bases[2];

  // Filling the array with different structs
  bases[0] = (Base*) malloc(sizeof(Base));
  bases[1] = (Base*) malloc(sizeof(Derived1));

  bases[1]->a = 5;
  Derived1 *d1 = (Derived1*) bases[1];

  if(d1->a == 5)
    printf("SUCCESS\n");

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我知道为什么这个例子有效,但它总能工作吗?是否有填充或类似的东西可以防止这种情况,或者C标准是否支持这个?

das*_*ght 5

根据C99规则,这两个struct是不兼容的:

如果它们的标记和成员满足以下要求,则在单独的转换单元中声明的两个结构,联合或枚举类型是兼容的:如果使用标记声明一个,则另一个应使用相同的标记声明.如果两者都是完整类型,则以下附加要求适用:其成员之间应存在一对一的对应关系,使得每对相应成员都声明为具有兼容类型,并且如果相应对的一个成员是使用名称声明,另一个成员使用相同的名称声明.对于两个结构,相应的成员应按相同的顺序声明.

您的代码在成员之间断开了一对一的对应关系,因此根据标准,这将是无效的:

Base *d1 = (Base*) bases[1];
d1->a=5; // Not valid
Run Code Online (Sandbox Code Playgroud)

幸运的是,您可以通过嵌入BaseDerived1以下内容轻松使其有效:

typedef struct Derived1 {
  Base base;
  // adding some other members to this struct
  int otherMember;
  int otherMember2;
} Derived1;
Run Code Online (Sandbox Code Playgroud)

根据C99,

指向适当转换的结构对象的指针指向其初始成员

因此,这是有效的:

Base *d1 = (Base*) bases[1];
d1->a=5; // Valid
Run Code Online (Sandbox Code Playgroud)

注意: 此问答讨论了严格别名的相关主题.