通过在作为另一个结构而不是第一个成员的子集的一个结构之间转换指针来实现 C 中的继承是否合法?

2023-12-02

现在我知道我可以通过将指针强制转换为struct到这个的第一个成员的类型struct.

然而,纯粹作为一种学习经历,我开始想知道是否可以以稍微不同的方式实现继承。

这段代码合法吗?

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

struct base
{
    double some;
    char space_for_subclasses[];
};

struct derived
{
    double some;
    int value;
};

int main(void) {
    struct base *b = malloc(sizeof(struct derived));
    b->some = 123.456;
    struct derived *d = (struct derived*)(b);
    d->value = 4;
    struct base *bb = (struct base*)(d);
    printf("%f\t%f\t%d\n", d->some, bb->some, d->value);
    return 0;
}

这段代码似乎产生了预期的结果,但据我们所知,这远不能证明它不是 UB。

我怀疑这样的代码可能合法的原因是我看不到这里可能出现的任何对齐问题。但当然,这远不知道不会出现此类问题,即使确实不存在对齐问题,代码仍可能因其他原因而成为 UB。

  • 上述代码有效吗?
  • 如果不是,有什么办法让它有效吗?
  • Is char space_for_subclasses[];必要的?删除此行后,代码似乎仍然正常运行

当我阅读该标准第 §6.2.6.1/P5 章时,

某些对象表示不需要表示对象类型的值。如果存储的 对象的值具有这样的表示形式,并由左值表达式读取:做 没有字符类型,行为未定义。 [...]

所以,只要space_for_subclasses is a char (数组衰减到指针) 成员并且你用它来读取值,你应该没问题。


也就是说,要回答

Is char space_for_subclasses[];必要的?

Yes, it is.

引用§6.7.2.1/P18,

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可以 数组类型不完整;这称为灵活的阵列成员。在大多数情况下, 灵活数组成员被忽略。特别是,结构的大小就好像 灵活的数组成员被省略,除了它可能有比 省略意味着。然而,当一个. (or ->) 运算符有一个左操作数,即 (指向)具有灵活数组成员和正确操作数名称的结构 成员,它的行为就好像该成员被最长的数组替换(具有相同的 元素类型)不会使结构大于正在访问的对象;这 数组的偏移量应保持灵活数组成员的偏移量,即使这会有所不同 来自替换阵列的阵列。如果这个数组没有元素,它的行为就好像 它有一个元素,但如果尝试访问该元素,则行为未定义 元素或生成一个超过它的指针。

删除它,您将访问无效内存,导致未定义的行为。但是,在您的情况(第二个片段)中,您没有访问value无论如何,所以这不会成为问题here.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过在作为另一个结构而不是第一个成员的子集的一个结构之间转换指针来实现 C 中的继承是否合法? 的相关文章

随机推荐