通过在一个结构之间转换指针而不是第一个成员,在C中实现继承是合法的吗?

现在我知道我可以通过将指向结构的指针强制转换为此结构的第一个成员的类型来实现继承.

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

这段代码合法吗?

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

This code seems to produce desired results,但正如我们所知,这远非证明它不是UB.

我怀疑这样的代码可能合法的原因是我看不到这里可能出现的任何对齐问题.但是,当然这远远不知道没有出现这样的问题,即使确实没有对齐问题,代码可能仍然是UB由于任何其他原因.

>以上代码有效吗?
>如果不是,有什么方法可以使它有效吗?
>是char space_for_subclasses [];必要? Having removed this line the code still seems to be behaving itself

最佳答案
这或多或少与struct sockaddr使用的穷人的继承相同,并且对于当前的编译器来说它是不可靠的.演示问题的最简单方法是这样的:

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

struct base
{
    double some;
    char space_for_subclasses[];
};
struct derived
{
    double some;
    int value;
};

double test(struct base *a, struct derived *b)
{
    a->some = 1.0;
    b->some = 2.0;
    return a->some;
}

int main(void)
{
    void *block = malloc(sizeof(struct derived));
    if (!block) {
        perror("malloc");
        return 1;
    }
    double x = test(block, block);
    printf("x=%g some=%g\n", x, *(double *)block);
    return 0;
}

如果a-> some和b->标准字母允许某些对象是同一个对象,那么这个程序将需要打印x = 2.0 some = 2.0,但是对于某些编译器和某些条件(它将不会在所有优化级别发生,并且您可能必须将测试移动到其自己的文件)它将打印x = 1.0 some = 2.0.

标准的字母是否确实允许a-> some和b-> some某些是相同的对象是有争议的.请参阅http://blog.regehr.org/archives/1466及其链接到的纸张.

转载注明原文:通过在一个结构之间转换指针而不是第一个成员,在C中实现继承是合法的吗? - 代码日志