extern "C" 完整讲解(C++ 专用,解决 C/C++ 混编符号兼容)
1. 核心作用
C++ 支持函数重载、命名空间、类成员函数,编译时会对函数名做名字改编(Name Mangling); C 语言没有重载,不会修改函数名。extern "C"的作用:告诉 C++ 编译器,这段代码按照 C 语言规则编译、生成 C 风格符号,不做名字改编。
2. 两种使用场景
场景 1:C++ 调用 C 写的库(最常用)
C 库头文件(比如 stdio.h、自定义 C 静态库)直接在 C++ 里引入会链接报错,因为符号名对不上。
标准写法(头文件兼容 C/C++):
#ifdef __cplusplus extern "C" { #endif // C 风格函数声明 void func(int a); int add(int x, int y); #ifdef __cplusplus } #endif含义:
- 如果是 C++ 编译器编译,包裹在
extern "C" {}内,函数按 C 规则导出符号; - 如果是 C 编译器,
__cplusplus未定义,直接忽略这段标记。
场景 2:C 调用 C++ 写的函数
C 不能识别 C++ 改编后的函数名,C++ 对外暴露接口必须加extern "C":
// .cpp 文件 extern "C" void cpp_api() { // 内部可以正常写C++代码:类、string、重载等 }编译后cpp_api符号名不变,C 代码可以直接void cpp_api();调用。
3. 对比有无 extern "C" 的符号差异
举个例子:void test(int)
- 不加 extern "C"(纯 C++) GCC 改编后符号:
_Z4testi - 加 extern "C" 符号直接为:
test
链接器去库中找符号时名字必须完全匹配,名字不一致就报undefined reference。
4. 关键限制
extern "C"内部不能写 C++ 重载函数C 不支持重载,多个同名 C 函数会符号冲突:extern "C" { void f(int); void f(double); // 编译报错,C不允许重载 }- 只能修饰全局普通函数 / 全局变量,不能修饰类、成员函数、模板。
extern "C"只影响编译阶段符号生成,函数内部逻辑依然可以完整使用 C++ 特性(类、STL、异常等)。