我正在编写一个 C 库,它使用一些简单的面向对象继承,如下所示:
struct Base {
int x;
};
struct Derived {
struct Base base;
int y;
};
现在我想将 Derived* 传递给一个采用 Base* 的函数,如下所示:
int getx(struct Base *arg) {
return arg->x;
};
int main() {
struct Derived d;
return getx(&d);
};
这是可行的,当然也是类型安全的,但编译器不知道这一点。有没有办法告诉编译器这是类型安全的?我在这里只关注 GCC 和 clang,因此欢迎特定于编译器的答案。我模糊地记得看到一些使用此方法执行此操作的代码__attribute__((inherits(Base))
或诸如此类的事情,但我的记忆可能在撒谎。
这在 C 中是安全的,除了你应该将参数转换为Base *
。禁止别名(或者更准确地说,标准 C 不支持别名)的规则位于 C 2011 6.5 中,其中第 7 段指出:
对象的存储值只能由具有以下类型之一的左值表达式访问:
— 与对象的有效类型兼容的类型,
…
这条规则阻止我们使用指针float
,将其转换为指向的指针int
,并取消引用指向的指针int
访问float
as an 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 约束。但是,如果您自己进行转换,则是合法的。如果需要,可以将转换构建到调用该函数的预处理器宏中,以便代码看起来仍然像一个简单的函数调用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)