【问题标题】:Does this C inheritance implementation contain undefined behavior?这个 C 继承实现是否包含未定义的行为?
【发布时间】:2017-01-25 17:58:00
【问题描述】:
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;
}

程序编译(无警告)并运行良好并按预期打印69。我从未见过任何实现这种继承技术的代码,所以我很犹豫是否将其视为“OK”。

编辑:把孙子变成一个孩子怎么样?中代转换也可以吗?

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;
}

【问题讨论】:

  • 这被称为类型双关语吗?就像在 Win32 中一样,NMHDR 和第一个成员是指向 NMHDR 的指针的结构?我不确定
  • 您可能还想查看与您的问题相关的man 3 offsetof
  • 您可能从未见过实现该技术的代码,但我确实编写过这样的代码。在说服自己它的行为是明确定义的之后,基于 Sourav 在他的回答中提出的基本相同的论点。我相信我并不是第一个编写此类代码的人。
  • 当然,您实际上并不需要演员表。您可以取而代之的是相应成员的地址。例如,print_parent_val(&g.child.parent)

标签: c struct language-lawyer


【解决方案1】:

如我所见,此处没有未定义行为的范围。

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

在结构对象中,非位域成员和位域所在的单元 驻留的地址按照声明的顺序增加。 指向 a 的指针 结构对象,经过适当转换,指向其初始成员(或者如果该成员是 位域,然后到它所在的单元),反之亦然。 可能有未命名的 在结构对象内填充,但不在其开头。

因此,使用当前的 sn-p(和方法),你应该很高兴。

【讨论】:

  • 如您所见,我对我的问题进行了一些修改,但我相信这句话也能回答它。
  • 你是正确的,结构的内存布局允许它工作,if 严格的别名不是一件事。 -fno-strict-aliasing,这是正确答案!
  • @HaldeanBrown 这里明确提到开头没有填充,那么这如何违反严格的别名规则?
  • @SanchkeDellowar 我相信你是对的,只要你坚持第一个成员变量。 :)
  • @HaldeanBrown 这种技术没有违反严格的别名。有一个parent对象在孩子的开头。
猜你喜欢
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-17
  • 2019-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多