我有一个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);
}

还有其他问题吗?还是应该完全不同地做?

最佳答案

对齐要求不会引起任何问题,这确实是C中伪造继承的默认方式。

但是,您的static_cast_B()不可移植(特别是void *算术,如果是unsigned,则转换为sizeof (void *) > sizeof (unsigned)-后者仍然可以工作,但是有点代码味道)。

我建议改用以下代码:

#include <stddef.h>

B* static_cast_B(A* a) {
  return (B*)((char*)a - offsetof(B, parent));
}

09-10 06:08
查看更多