Swift调用C++函数必须通过extern "C"封装为C ABI接口,参数返回值限于C兼容类型,字符串和对象需用const char*或opaque指针管理生命周期,链接失败多因符号未正确导出或构建配置错误。

Swift 调用 C++ 函数必须通过 C ABI 中转
Swift 不能直接链接或调用 C++ 符号,因为它的 FFI 只支持 C 风格接口。所有要暴露给 Swift 的 C++ 功能,都得先封装成 extern "C" 函数,禁用 name mangling。
- 在 C++ 头文件里用
extern "C"块包裹函数声明,且函数参数/返回值只能是 C 兼容类型(如int、double、const char*、struct,不能是std::string、std::vector、引用、重载函数) - 实现文件里同样用
extern "C"包裹定义,或直接在头文件中 inline 实现(避免 .cpp 文件参与链接) - Swift 项目需在 Bridging Header 中
#import "your_c_api.h",不能直接 import C++ 头
Xcode 工程里混编 C++ 和 Swift 的关键配置
不是加个文件就能跑,Xcode 默认把 .cpp 当作纯 C++ 编译,不会生成 Swift 可见的符号。
- 确保 C++ 实现文件后缀是
.mm(Objective-C++)或.cpp+ 手动设编译器为Apple Clang,但更稳妥的是统一用.mm并在其中写extern "C"函数 - 在 Build Settings 中检查
Header Search Paths是否包含 C++ 头路径,Always Search User Paths设为No -
Defines Module必须为Yes,否则 Swift 无法识别模块化导入;但 Bridging Header 方式下此项可关 - 如果用 Swift Package Manager,需在
targets的dependencies或sources中显式列出 C/C++ 源,并用cSettings控制头路径
如何安全传递字符串和对象指针
C++ 和 Swift 内存模型不同,不能裸传 std::string* 或类实例指针——Swift 不认识析构逻辑,ARC 也不管它。
- 字符串统一用
const char*+ 长度,或用CFStringRef(需桥接);Swift 侧用String(cString:)转换,注意空终止 - 复杂对象用 opaque 指针:C++ 侧定义
typedef struct OpaqueHandle *HandleRef;,导出HandleRef create_handle()、void destroy_handle(HandleRef)等函数 - Swift 中用
UnsafeMutableRawPointer?存储该指针,调用前判空,deinit里务必调用销毁函数,否则 C++ 对象泄漏 - 别用
reinterpret_cast强转 Swift 类型指针,会触发 undefined behavior
常见错误:Undefined symbol: _some_cpp_function
这是最典型的链接失败,说明 Swift 找不到符号,不是语法错,而是 ABI 或构建链路断了。
- 检查函数是否真的在
extern "C"块内声明 —— 单独写extern "C" void f();不够,必须整个声明块被包裹 - 用
nm -gU your_library.a | grep some_cpp_function确认符号是否存在且未 mangling;若看到_Z...开头,说明没走 C ABI - 确认该函数实现在被链接的静态库或 framework 中,而不是仅存在于未编译的头文件里
- Swift 调用时函数名不带下划线前缀,但 Mach-O 符号可能有,Xcode 会自动处理;手动写
import时别加_
真正麻烦的从来不是“怎么写通”,而是生命周期管理——C++ 对象谁 alloc 谁 dealloc,Swift 的 Unsafe* 指针不会自动帮你记着。稍不注意,就是野指针或 double-free。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











