根本原因是C++名称修饰导致符号不匹配;加extern "C"可禁用修饰并统一ABI,但需条件编译保护头文件,且仅适用于C兼容实体(函数、变量、typedef结构体),不可用于类、模板或static函数。

为什么C++调用C函数会报“undefined reference”
根本原因是C++编译器对fun这类函数名做了名称修饰(name mangling),比如把void fun(int)编译成_Z3funi;而C编译器只生成fun这个符号。链接时,C++代码去找_Z3funi,但C目标文件里只有fun,自然找不到。
加extern "C"就是告诉C++编译器:“别修饰这个名字,按C的方式生成符号”,让两边符号名对上。
- 不加
extern "C":C++代码编译出修饰名,链接失败 - 加了之后:C++生成的符号名和C一致,链接成功
- 错误现象常见于
undefined reference to 'xxx',尤其在链接C库(如libpng、zlib)时
怎么写才不会被C编译器报错
C头文件如果直接被C++包含,用extern "C"没问题;但如果也被C源文件包含,C编译器不认识extern "C"语法,会直接报错。
必须用条件编译包裹:
立即学习“C++免费学习笔记(深入)”;
#ifdef __cplusplus
extern "C" {
#endif
<p>void c_api_init(void);
int c_api_process(const char* data, int len);</p><h1>ifdef __cplusplus</h1><p>}</p><h1>endif</h1><p>-
__cplusplus是C++编译器预定义宏,C编译器没有这个宏,所以中间的extern "C"块会被跳过 - 漏掉
#ifdef __cplusplus保护,C文件一include就编译失败 - 不能只在.cpp里加——头文件才是跨语言共享的枢纽
extern "C"能修饰类或模板吗
不能。C语言没有类、模板、命名空间、重载这些概念,extern "C"只适用于C兼容的实体:函数声明、全局变量、typedef结构体。
- 以下写法是错的:
extern "C" class MyClass { ... }; - 以下也不行:
extern "C" template<typename t> T max(T a, T b);</typename> - 连
static函数都不能加extern "C"——它本身就不生成外部符号,加了也没意义 - 如果想从C调用C++逻辑,只能把接口封装成普通函数,并用
extern "C"导出
extern "C"会影响调用约定和异常传播吗
会。它不只是关掉名字修饰,还强制使用C的ABI(Application Binary Interface):
- 函数调用约定变成
cdecl(参数从右往左压栈,调用者清理栈),不是C++默认的thiscall或fastcall - 禁止在
extern "C"函数体内抛C++异常;若C代码调用它,异常一旦越界就导致未定义行为(通常是崩溃) - 返回类型和参数类型必须是C兼容的:不能传
std::string、std::vector,得用const char*、int*等 - 结构体里也不能有虚函数、非POD成员,否则C端无法安全读写
真正容易被忽略的是ABI层面的约束——光让名字对上只是第一步,数据怎么传、谁负责清理、出错怎么处理,都得按C那一套来。


















