有没有办法让GCC/Clang知道C中的继承?

Shu*_*hum 4 c inheritance gcc clang

我正在编写一个C库,它使用一些简单的面向对象的继承,就像这样:

struct Base {
    int x;
};

struct Derived {
    struct Base base;
    int y;
};
Run Code Online (Sandbox Code Playgroud)

现在我想将Derived*传递给一个带有Base*的函数:

int getx(struct Base *arg) {
    return arg->x;
};

int main() {
    struct Derived d;
    return getx(&d);
};
Run Code Online (Sandbox Code Playgroud)

这是有效的,当然是类型安全的,但编译器不知道这一点.有没有办法告诉编译器这是类型安全的?我只关注GCC并在这里铿锵作响,因此欢迎编译器特定的答案.我有一些模糊的记忆,看到一些代码可以使用__attribute__((inherits(Base))或类似的东西,但我的记忆可能在撒谎.

Eri*_*hil 5

这在C中是安全的,除非您应该将参数强制转换为Base *.禁止混淆的规则(或更准确地说,不包括在标准C中支持混淆)的规则在C 2011 6.5中,其中第7段规定:

对象的存储值只能由具有以下类型之一的左值表达式访问:

- 与对象的有效类型兼容的类型,

...

此规则阻止我们采取一个指针float,将其转换为指针int,并取消引用指针int访问float作为int.(更准确地说,它并不妨碍我们尝试,但它会使行为不明确.)

您的代码似乎违反了这一点,因为它Derived使用Base左值访问对象.然而,指针转换成Derived的指针Base被C 2011 6.7.2.1第15点的状态的支持:

...指向适当转换的结构对象的指针指向其初始成员...

因此,当我们将指针转换为指向Derived的指针时Base,我们实际拥有的不是Derived使用与其不同的类型(禁止)的指向Derived对象的指针,而是指向使用其实际类型的对象的第一个成员的指针,Base这是完全没问题的.

关于编辑:最初我声明函数参数将被转换为参数类型.但是,C 6.5.2.2 2要求每个参数都有一个类型可以分配给具有相应参数类型的对象(具有const删除的任何限定条件),6.5.16.1要求在将一个指针指向另一个时,它们具有兼容类型(或满足此处不适用的其他条件).因此,将指针传递Derived给一个使指针Base违反标准C约束的函数.但是,如果您自己执行转换,则是合法的.如果需要,转换可以内置到调用函数的预处理器宏中,这样代码看起来仍然像一个简单的函数调用.