通过展开继承是否违反了严格的别名规则?

Mar*_*lny 7 c inheritance struct strict-aliasing

我有一个继承自struct Base的struct X. 但是,在我目前的设置中,由于对齐,X的大小为24B:

typedef struct {
    double_t a;
    int8_t b;
} Base;

typedef struct {
    Base base;
    int8_t c;
} X;
Run Code Online (Sandbox Code Playgroud)

为了保存内存,我想展开Base结构,所以我创建了包含Base的字段的struct Y(以相同的顺序,总是在struct的开头),所以struct的大小是16B :

typedef struct {
    double_t base_a;
    int8_t base_b;
    int8_t c;
} Y;
Run Code Online (Sandbox Code Playgroud)

然后我将在一个方法中使用struct Y的实例,该方法需要一个指向Base结构的指针:

void print_base(Base* b)
{
  printf("%f %d\n", b->a, b->b);
}
// ...
Y data;
print_base((Base*)&data);
Run Code Online (Sandbox Code Playgroud)

上面的代码是否违反了严格的别名规则,并导致未定义的行为?

Lun*_*din 8

首先,Base并且Y不是标准6.2.7定义的兼容类型,所有成员必须匹配.

YBase*不创建严格别名违规的情况下访问a ,Y需要是"聚合类型"(它是),其中包含Base其成员之间的类型.它不是.

所以这是一个严格别名违规,此外,由于YBase是不兼容的,他们可能有不同的内存布局.这就是重点,你为了这个原因制作了不同的类型:)

在这种情况下你可以做的是使用具有共享一个共同初始序列的结构成员的联合,这是一个特殊的允许案例.来自C11 6.5.2.3的有效代码示例:

union {
  struct {
    int alltypes;
  } n;
  struct {
    int type;
    int intnode;
  } ni;
  struct {
    int type;
    double doublenode;
  } nf;
} u;

u.nf.type = 1;
u.nf.doublenode = 3.14;
/* ... */
if (u.n.alltypes == 1)
  if (sin(u.nf.doublenode) == 0.0)
Run Code Online (Sandbox Code Playgroud)