指向 C++ 类的 C 结构指针
Posted
技术标签:
【中文标题】指向 C++ 类的 C 结构指针【英文标题】:C struct pointer to C++ class 【发布时间】:2021-01-12 23:45:44 【问题描述】:我正在编写一个将加载到 C++ 程序中的 C 共享库。这个程序中有一个我需要访问的对象,所以我将使用一个结构指针。但我不太确定如何使 C 结构指针指向 C++ 类,因为它还包含函数(构造函数、析构函数等)。我认为这是可能的,因为结构只是保存数据,这意味着我可以按照与内存中的 C++ 类匹配的方式来排列它。示例:
//C++ class
class test
public:
int number;
char* string;
public:
test();
~test();
void function(int new_number);
void function(char* new_string);
obj;
//C struct pointer
struct test_t
//???
;
//...
struct test_t* p_obj = (struct test_t*)addr_of_obj;
有什么想法吗?
编辑:我无法编辑正在将库加载到的程序的源代码。我强制它加载这个库,它将为我访问和修改内存。
【问题讨论】:
为什么 c 库必须知道将加载它的其他项目?我认为应该是相反的。class test : test_t whatever; ;
?这不需要你弄清楚如何将test_t
变成一个类——只需从test_t
继承即可。
共享库将用C编译,程序已经用C++编译。我不能将 C++ 类继承到 C 代码中。而且我不能修改目标程序的源代码,这就是我使用这个库来访问和修改内存的原因。 “测试”类只是一个例子。
您可以弄清楚特定实现如何布置特定 C++ 类,并定义与该布局匹配的 C 结构(在您的示例中,struct test_t int number; char* string; ;
可能会起作用)。这将是脆弱的,在编译器之间不可移植,甚至可能在同一编译器的不同版本之间,或者在相同版本但使用不同选项进行编译之间。 C++ 类的二进制布局没有标准化,实现范围很广。
【参考方案1】:
经过一些测试,我认为这个问题的答案是:取决于编译器和类。我将在下面给出的示例是在 Linux 上使用 GCC 和 G++ 编译的(似乎也可以使用 clang 和 clang++)。
示例 1 - 具有一些变量、构造函数、析构函数和重载函数的类 - 没什么特别之处。
//C++ class
class test
private:
int number;
char* string;
public:
test() this->number = 0; this->string = (char*)""; this->boolean = false;
~test()
void function(int num) this->number = num;
void function(char* str) this->string = str;
int get_number() return this->number;
char* get_string() return this->string;
bool boolean;
;
//C structure
//To create a struct pointer for this class, I just had to ignore the functions.
struct test_t
int number;
char* string;
bool boolean;
;
示例 2 - 一个包含虚函数的类。在这种情况下,我们必须在结构的开头添加一个额外的指针参数。这将与该类的虚函数表对齐,由于虚函数而不再隐藏。
//C++ class
class test
private:
int number;
char* string;
public:
test() this->number = 0; this->string = (char*)""; this->boolean = false;
~test()
virtual void v_function() printf("virtual function\n");
virtual void v_function2() printf("another virtual function\n");
void function(int num) this->number = num;
void function(char* str) this->string = str;
int get_number() return this->number;
char* get_string() return this->string;
bool boolean;
;
//C structure
//It is the same as before, but with the VFT pointer
struct test_t
void** vptr; //A pointer to function addresses (void**)
int number;
char* string;
bool boolean;
;
总之,100% 确保 C 结构指针与 C++ 类对齐的唯一方法是查看内存并手动对齐。你可以通过在你的结构中放置垫子来跳过一些变量:
//C++ class
class test
private:
int number;
std::vector<std::string> vector;
char* string;
public:
test() this->number = 0; this->string = (char*)""; this->boolean = false;
~test()
virtual void v_function() printf("virtual function\n");
virtual void v_function2() printf("another virtual function\n");
void function(int num) this->number = num;
void function(char* str) this->string = str;
int get_number() return this->number;
char* get_string() return this->string;
bool boolean;
;
//C structure
struct test_t
void** vptr;
int number;
char vector[24]; //std::vector<std::string> pad (24 bytes long)
char* string;
bool boolean;
;
【讨论】:
这是错误的,只要你的 C++ 类有一些virtual
函数(或析构函数)。 virtual method table 通常是一些 hidden 指针。而且你需要考虑析构函数和 C++ 异常(所以throw
)
我明白你在说什么。我用虚函数进行了测试,结果搞砸了:_vptr.test = 0x555555557d98 实现这一点并使代码易于支持的方法是使用 C++ 代码中的 C 定义。也许使用私有实现来减少兼容性问题。
//C struct - non-static data
struct test_t
int number;
char* string;
;
test_t
的 C++ 包装器。
// C++ interface
struct test_t;
struct test
test_t *priv; //private implementation
public:
// methods.
;
【讨论】:
【参考方案3】:class
es 和 struct
s 在内存中的布局方式并未由 C 和 C++ 标准定义,而是在特定于平台的应用程序二进制接口 (ABI) 文档中进行了布局。为确保安全,您必须确保布局匹配。如果任何功能是虚拟的,您肯定会遇到问题。
更安全的选择是将extern "C"
结构嵌入到您的C++ 类中,或者从C 代码中隐藏该类,只允许通过extern "C"
访问器函数进行访问。
【讨论】:
以上是关于指向 C++ 类的 C 结构指针的主要内容,如果未能解决你的问题,请参考以下文章