如何在Rust动态库中调用C++应用的Core类?
在Rust动态库中调用C++ Core类的实现方案
1. 修正Rust中的Core类型定义与全局实例存储
Rust中的不透明结构体无需#[repr(C)],我们仅用它标记C++ Core类的指针类型,不需要依赖其内部布局:
// 不透明结构体,仅用于标识C++ Core类的指针类型 pub struct Core; // 全局存储C++传入的Core实例指针 // 注意:static mut是非线程安全的,单线程环境可直接使用;多线程需加锁(比如用Mutex) static mut CORE_INSTANCE: Option<*mut Core> = None;
2. 实现初始化函数(供C++调用)
初始化函数的参数类型对应C的Core*,需添加#[no_mangle]禁止Rust编译器修改函数名,保证C能正确寻址:
#[no_mangle] pub extern "C" fn init_core(core_instance: *mut Core) { unsafe { CORE_INSTANCE = Some(core_instance); } }
3. 调用C++类的成员函数
由于C++成员函数隐含this指针,调用约定与普通C函数不同,有两种可行方案:
方案一:C++提供C风格包装函数(推荐,安全且跨编译器)
在C++代码中为printMessage编写C兼容的包装函数,将this指针显式作为参数传入:
extern "C" { void core_print_message(Core* core, const char* text, int length) { core->printMessage(text, length); } }
然后在Rust中声明并调用该函数:
// 声明C++导出的包装函数 extern "C" { fn core_print_message(core: *mut Core, text: *const u8, length: i32); } fn foo() { unsafe { if let Some(core) = CORE_INSTANCE { // C++需要以'\0'结尾的字符串,这里用b"Hello\0"生成符合要求的字节序列 core_print_message(core, b"Hello\0".as_ptr(), 5); } } }
方案二:直接调用C++成员函数(unsafe,依赖编译器实现)
这种方式无需修改C++代码,但依赖编译器对成员函数的布局实现(如GCC/Clang的调用约定),风险较高:
// 定义对应C++成员函数的函数指针类型,第一个参数为this指针 type PrintMessageFn = unsafe extern "C" fn(this: *mut Core, text: *const u8, length: i32); fn foo() { unsafe { if let Some(core) = CORE_INSTANCE { // 将C++成员函数地址转换为函数指针,需替换为实际的成员函数地址 // 成员函数地址可由C++传递给Rust,或依赖编译器布局假设(不推荐) let print_fn: PrintMessageFn = std::mem::transmute(0x12345678); print_fn(core, b"Hello\0".as_ptr(), 5); } } }
注意:不同编译器(如MSVC与GCC)的成员函数调用约定可能不同,这种方式易触发未定义行为,仅在无法修改C++代码时使用。
4. C++侧调用示例
在C++中初始化Core实例,并调用Rust的初始化函数:
#include <iostream> class Core { public: void printMessage(const char* text, const int length) { std::cout << std::string(text, length) << std::endl; } }; // 声明Rust导出的初始化函数 extern "C" void init_core(Core* core); int main() { Core core; init_core(&core); // 触发Rust中的foo函数调用(需Rust导出对应触发函数) return 0; }
内容的提问来源于stack exchange,提问作者Darimity
相关产品推荐
相关产品推荐

