此C继承实现是否包含未定义的行为?

San*_*war 7 c struct language-lawyer

struct parent
{
    char a;
    char b;
};

struct child
{
    struct parent parent;
    int c;
    char d;
};

struct grandchild
{
    struct child child;
    long e;
};

void print_parent_val(struct parent *p)
{
    printf("%d\n", p->a);
}

int main (int argc, char **argv)
{
    struct grandchild g;
    g.child.parent.a = 69;
    print_parent_val((struct parent *)&g);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序编译(没有警告)并运行正常并按69预期打印.我从未见过任何实现此继承技术的代码,因此我非常犹豫地认为这是"好".

编辑:如何将孙子变成一个孩子?中期转换也可能吗?

void print_parent_val(struct child *c)
{
    printf("%c\n", c->d);
}

int main (int argc, char **argv)
{
    struct grandchild g;
    g.child.parent.a = 69;
    g.child.d = 'w';
    print_parent_val((struct child *)&g);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Sou*_*osh 7

正如我所看到的,有没有未定义行为的范围在这里.

引用C11,章节§6.7.2.1,结构和联合说明符,(强调我的)

在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址.指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然.结构对象中可能存在未命名的填充,但不是在其开头.

所以,使用当前的片段(和方法),你应该很高兴.