gpt4 book ai didi

c++ - 在 C : Will alignment break my neck? 中伪造继承

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:38:09 25 4
gpt4 key购买 nike

我有一个 C 结构,用于各种 C 和 C++ 代码(通过 extern "C")。

#ifdef __cplusplus
extern "C" {
#endif

typedef struct A A;
struct A {
/*some members*/
};

#ifdef __cplusplus
}
#endif

分配、初始化和释放是由我控制的独立成员函数完成的,但我不控制对成员的访问,因为它们可以在任何地方访问。

问题是,我无法更改整个系统中大量使用的 header 中struct 的定义,但我仍然想扩展类型并添加一些成员。由于这必须编译为 C++ 和 C,我不能简单地创建派生类型 struct B : public A。所以我的想法是将这种类型添加到 cpp 文件中:

#ifdef __cplusplus
extern "C" {
#endif

typedef struct B B;
struct B {
A parent; // <---- public inheritance
/*some members*/
};

#ifdef __cplusplus
}
#endif

现在,我可以修改 cpp 文件中的所有函数,但我仍然必须在编译单元之外分发和接受 A*,因为没有人知道 B 是什么.

所以,我想知道是否有一种理智且定义明确的方法可以做到这一点。我可以简单地将我的 B* 转换为 A*s 并返回,还是我必须显式转换它们:

A* static_cast_A(B* b) {
return &(b->parent);
}
B* static_cast_B(A* a) {
B* const b = 0;
unsigned const ptrdiff = (unsigned)((void*)(&(b->parent)));
return (B*)(((void*)a)-ptrdiff);
}

这还有什么问题吗?还是我应该完全不同地做?

最佳答案

只要您不在struct B 中引入虚表(通过添加虚方法或析构函数),并且该结构的parent 成员是第一个元素, 然后将 B 大小写为 A 是安全的。

A 转换为 B 也是安全的,但前提是原始指针实际上指向 B 而不是其他东西,显然,只像 A 结构本身。

如果 parent 不是结构 B 的第一个成员,您将不得不使用 container_of 宏,如 Linux 内核所示,例如。它消除了成员指针偏移量(即可以找到一些很好的解释 here )。

此外,默认情况下,两个结构将具有相同的对齐方式。如果您调整其中一个结构对齐方式,我不确定编译器如何将 A 放入 B 中。我想这取决于编译器,但应该很容易弄清楚。

如果 B 有一个虚拟表,您必须了解编译器内部知识才能正确转换指针。例如,x86_64 上的 GCC 添加了 8 个字节的偏移量,因此您必须在转换时手动偏移它。但这在虚拟继承(虚拟基类)的情况下不起作用,要解决你必须诉诸于使用 RTTI 等......但这超出了你的问题范围,我建议你不要往那边走。

希望对您有所帮助。

关于c++ - 在 C : Will alignment break my neck? 中伪造继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12443732/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com