Rust调用C++函数前必须使用extern "C"声明并确保ABI对齐,否则链接失败或运行时崩溃;结构体需repr(C)与#pragma pack(1)匹配;字符串用const char*+长度;指针传入需手动管理生命周期;资源释放须双向同步。

rust 调用 c++ 函数前必须检查 extern "C" 和 ABI 对齐
rust 无法直接调用 C++ 的 name mangling 符号,所有暴露给 rust 的函数必须用 extern "C" 声明,否则链接失败或运行时崩溃。这不是可选优化,是硬性前提。
常见错误现象:undefined reference to `xxx`(链接时报错)、segmentation fault(符号解析错位后跳转到非法地址)。
-
extern "C"必须加在 C++ 头文件声明和实现两端,不能只加一头 - 避免在
extern "C"块里放 C++ 特性:类、引用、重载、模板——这些都会破坏 C ABI 兼容性 - 结构体字段顺序、对齐方式必须显式控制:C++ 端用
#pragma pack(1)或alignas,rust 端用#[repr(C)],否则字段偏移错位,读写内存越界 - 字符串传递别用
std::string,统一用const char*+ 长度参数;rust 侧用CStr::from_ptr转换,且必须确保 C++ 字符串以\0结尾
rust 传指针进 c++ 时,生命周期和所有权必须手动对齐
c++ 没有 borrow checker,rust 传过去的裸指针(*const T / *mut T)一旦被 c++ 保存或异步使用,就脱离了 rust 的生命周期管理——这是最常引发 use-after-free 的地方。
典型场景:c++ 注册一个回调函数,rust 把某个 &str 的指针传进去,回调触发时 rust 原变量早已释放。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- rust 侧若需长期持有数据供 c++ 使用,必须用
Box::leak或全局static mut(慎用),并配套设计明确的释放接口 - c++ 不得 free rust 分配的内存(如
Box::into_raw出来的指针),除非 rust 显式导出free_XXX函数且 c++ 严格调用它 - 避免把
&T直接转成裸指针传入 c++;优先用std::ptr::addr_of!(rust 1.75+)代替&*x,防止无意中触发 dereference - 如果 c++ 需要修改 rust 数据,rust 侧必须用
UnsafeCell包裹,并确保同一时间没有其他活跃的不可变引用
rust 中调用 c++ 代码必须用 unsafe 块,但 unsafe 范围要最小化
只要涉及 extern "C" 函数调用、裸指针解引用、静态变量访问,rust 就强制要求 unsafe 块。这不是形式主义,而是明确标出“此处绕过了编译器安全检查”的边界。
容易踩的坑:把整个 FFI 封装函数包在一个大 unsafe 块里,结果内部逻辑出错(比如空指针没判)也归为“unsafe 已覆盖”,掩盖真实问题。
- 每个
unsafe块只包裹真正需要绕过检查的那一两行,比如std::ptr::read或ffi_func(...) - 在
unsafe块外做所有前置校验:指针非空、长度合法、枚举值在有效范围内——把 panic 点留在安全区 - 用
std::ffi::CStr替代std::ffi::CString处理输入字符串,前者不拷贝,后者可能因嵌入\0而 panic,且 panic 发生在 safe 区更易定位 - 如果 c++ 接口返回错误码,rust 侧立即用
Result封装,不要让错误穿透到上层业务逻辑
c++ 端释放资源时,rust 必须同步失效对应句柄或指针
双方各自管理资源时,最容易漏掉“通知对方资源已销毁”这一步。比如 rust 持有一个 Handle 类型,底层指向 c++ new 出的对象,c++ delete 后 rust 还拿着旧地址继续用,就是野指针。
这不是理论风险,是实际 crash 高发区,尤其在异常路径或提前退出时。
- c++ 侧提供明确的
destroy_xxx函数,rust 在Drop实现里调用它,而不是依赖析构时机或手动调用 - rust 的 handle 类型应设为
#[repr(transparent)],内部用*mut std::ffi::c_void,禁止实现Copy,强制 move 语义 - 在
Drop::drop里加日志或断言(如assert!(!ptr.is_null())),避免 double-free;也可用std::sync::Once控制单次释放 - 如果 c++ 可能从多线程调用回调并释放资源,rust 侧 handle 必须用
Arc<Mutex<Option<*mut c_void>>>等同步机制保护,不能靠文档约定“用户保证单线程”
最麻烦的不是写通交互,而是当 c++ 代码变更(比如字段增减、析构逻辑调整)、rust 侧没同步更新 repr 或 drop 行为——这种 mismatch 往往不会编译报错,只会在特定输入下静默崩溃。


















