编译成动态库

.dll / .so 与 extern "C"

商用

◎学完你会

1C++ 源码 → 动态库

编译时加 -shared -fPIC(Linux)或 /LD(MSVC),产出 .so / .dll,供 Python 等语言加载。

g++ -shared -fPIC -o libx.so x.cpp
extern "C" int add(int a, int b);
看动态库编译命令。

2关键命令

写法含义
g++ -shared -fPIC -o libx.so src.cppLinux 编译成共享库(.so);-fPIC 位置无关代码
cl /LD src.cppWindows MSVC 编译成 DLL
extern "C" { int fn(...); }让函数按 C 命名规则导出(不 name-mangling),其他语言才好调用
__declspec(dllexport)Windows 显式导出符号
✅ extern "C" 是关键:C++ 会把函数名改写成带参数类型的符号(name mangling),Python ctypes 找不到;包一层 C 接口符号就稳定可查。

3为什么互操作走 C 接口

C 接口是最低公共标准:C 无重载、无名字改编、无 RAII 析构、异常不跨语言。跨语言边界要简单值类型 + 显式生命周期,别让异常/智能指针/重载直接暴露出去。

extern "C"{ int add(int a,int b){ return a+b; } // 简单、稳定、可被 ctypes 找到 void* create(); void destroy(void*); // 对象用句柄+成对创建/销毁 } // 不要在边界暴露:重载、模板、智能指针、跨语言抛异常
要点:跨语言调用尽量用 POD / C 兼容类型(int、double、指针);对象封装成不透明句柄(void* + create/destroy)。C++ 特性(重载、异常)一律留在 C++ 内部,边界只留 C 函数。

!易错点

① 忘了 extern "C"——C++ name mangling 后 Python 按名找不到函数。
② 边界暴露重载/模板——同名多符号,其他语言无法简单调用。
③ 跨语言抛 C++ 异常——异常机制不互通,会未定义行为/崩溃。
④ Windows 忘 dllexport / 忘了 32/64 位匹配——导出不到或位数不符加载失败。

?跨学科:动态库接口,像"工厂对外销售的标准件"

把 C++ 编成 .dll/.so 像工厂生产标准配件:自己内部用复杂工艺(重载、模板、智能指针),但对外只卖统一规格的标准件(extern "C" 的 C 函数:int add(int,int)),任何"买家"(Python/其他语言)按说明书就能用。

extern "C" 像给配件贴上统一型号标签(不 mangling),否则 C++ 给每款加料写一堆复杂型号名,别人根本对不上号。这也是"边界只留简单稳定接口、复杂东西藏内部"的工程智慧。

✎练一练

Linux 下把 C++ 编译成动态库(.so)的命令是?
Linux 动态库用 -shared -fPIC 编译成 .so;-c 只出目标文件。
extern "C" 包裹函数的主要作用是?
extern "C" 去掉 C++ 的名字改编,导出稳定的 C 符号,跨语言才好调用。
跨语言(如 C++/Python)边界不宜直接暴露的是?
跨语言边界用 POD/C 兼容类型 + 显式生命周期;重载/模板/智能指针/跨语言异常要留在 C++ 内部。