c++oding="utf-8" ?>
rust导出c兼容函数必须加extern "c"和#[no_mangle],参数返回值限c类型,c++头文件需extern "c"包裹声明,内存管理须双方约定free方式,构建需panic=abort且用release模式。

rust 生成 C 兼容 ABI 的函数必须加 extern "C" 和 #[no_mangle]
不加这两者,C++ 链接器根本找不到符号——Rust 默认用 mangling 编码函数名,且默认是 Rust ABI,C++ 完全不认。哪怕函数签名看起来“对得上”,链接时也会报 undefined reference to `xxx`。
实操建议:
-
extern "C"声明告诉 Rust 编译器:按 C 调用约定导出,禁用 Rust 特有 ABI(比如返回Result或泛型会直接编译失败) -
#[no_mangle]禁用名字混淆,让函数名在动态库中就是你写的原样,比如add_two,不是_ZN3lib7add_two17h9a8b7c6d... - 所有参数和返回值必须是 C 兼容类型:
i32、f64、*const u8、*mut i32等;不能用String、Vec、&str、Result - 如果要传字符串,用
*const std::ffi::CStr+std::ffi::CStr::from_ptr()解析;返回字符串则需返回*const i8并由 C++ 管理内存生命周期(或用malloc分配 + 提供free_string函数)
C++ 头文件里声明函数时必须用 extern "C" 包裹
否则 C++ 编译器会尝试对函数名做 C++ mangling,导致链接时和 Rust 导出的 C 符号对不上——即使 Rust 端用了 #[no_mangle],C++ 端没关 mangling 还是白搭。
常见错误现象:undefined reference to 'add_two',但 nm -D libmylib.so | grep add_two 明明能看到符号。
实操建议:
- 头文件中写成:
extern "C" { int32_t add_two(int32_t a, int32_t b); } - 不要只在单个函数前加
extern "C",而要用大括号块包裹所有 FFI 函数声明 - 确保头文件被 C++ 源文件
#include,且没有被#ifdef __cplusplus意外屏蔽 - 如果头文件也被 C 代码包含,可加
#ifdef __cplusplus判断,但对纯 C++ 项目非必需
Rust 返回堆内存给 C++ 时,谁负责 free 必须明确约定
这是最常踩的坑:Rust 用 Box::into_raw 或 CString::into_raw 返回指针,C++ 拿到后直接 delete 或 free ——行为未定义,大概率 crash。
原因:Rust 默认用系统 malloc(Linux 是 malloc),但 C++ 的 delete 可能调用的是 libc++ 的 operator delete,不一定匹配;更安全的方式是 Rust 提供配套的 free 函数。
实操建议:
- Rust 端分配内存用
std::alloc::alloc或CString::into_raw(底层也是alloc),并提供对应free_buffer(ptr: *mut u8)函数,内部调用std::alloc::dealloc - C++ 端拿到指针后,必须调用 Rust 提供的
free_buffer,而不是free或delete - 若返回固定大小结构体(如
struct Result { int code; const char* msg; }),可让 Rust 用Box::leak泄露内存,但需文档强约束:C++ 绝不释放该内存,仅读取 - 避免返回
Vec<u8></u8>的裸指针 + len 组合——除非你也一并导出free_vec并严格要求 C++ 调用它
构建时必须关闭 Rust 的 panic=abort,并用 cargo build --release 生成静态/动态库
默认 panic=unwind 会导致 Rust 抛异常时触发 C++ 的栈展开机制冲突,C++ 侧可能直接 abort;而 debug 构建的库体积大、含调试符号、性能差,不适合集成进 C++ 工程。
实操建议:
- 在
Cargo.toml中显式设置:[profile.release] panic = "abort"
- 用
cargo build --release --lib,输出target/release/libmylib.so(Linux)或.dylib(macOS)、.dll(Windows) - C++ 项目链接时,确保链接顺序正确:C++ 目标文件在前,Rust 库在后(尤其用
g++ -o app main.o -L. -lmylib) - Windows 下注意 Rust 默认生成 MSVC 工具链库,若 C++ 用 MinGW 编译会链接失败——统一用 MSVC 或改用
x86_64-pc-windows-gnu工具链
真正难的不是写通第一个函数,而是让字符串、错误码、内存生命周期在两边都稳住。很多问题不会在编译时报错,而是在某个特定输入路径下才触发段错误或内存泄漏——所以一定要测边界值、空字符串、null 指针、多线程并发调用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











