extern "c" 用于禁用c++名字修饰以实现c/c++混合链接,需用#ifdef __cplusplus条件包裹在头文件中,不可用于模板、重载函数、类成员及含c++类型的函数。

extern "C" 是用来解决名字修饰不兼容的问题
C++ 编译器会对函数名做 name mangling(名字修饰),比如 void foo(int) 可能被编译成 _Z3fooi;而 C 编译器只保留原始符号名 foo。当 C++ 代码要调用 C 编写的库(如 libc、libpng),或 C 代码要引用 C++ 函数时,链接器找不到匹配符号,直接报 undefined reference to 'xxx' 错误。
加 extern "C" 就是告诉 C++ 编译器:“这段声明/定义按 C 的规则处理符号名,别 mangling”。它不改变语法、不改变调用约定,只关掉名字修饰。
在头文件里用 extern "C" 包裹 C 函数声明
这是最常见也最安全的写法,尤其用于供 C++ 项目使用的 C 头文件(比如你自己写的 utils.h):
#ifdef __cplusplus
extern "C" {
#endif
<p>void c_function(int x);
int another_c_api(const char* s);</p><h1>ifdef __cplusplus</h1><p>}</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/ai/1214" title="灵图AI"><img
src="https://img.php.cn/upload/ai_manual/000/000/000/175680121880728.png" alt="灵图AI" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/ai/1214" title="灵图AI">灵图AI</a>
<p>灵图AI辅助设计平台</p>
</div>
<a href="/ai/1214" title="灵图AI" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/3851895a4c84" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">C语言免费学习笔记(深入)</a>”;</p><h1>endif</h1><p>- 必须用
#ifdef __cplusplus包裹,否则 C 编译器会报error: expected identifier or '(' before string constant - 不要在函数定义处(.c 文件里)加
extern "C"—— C 编译器不认识它 - 如果头文件只被 C++ 代码包含,可以省略条件宏,但加上更健壮
在 C++ 源文件里用 extern "C" 声明 C 库函数
当你没权限改 C 头文件(比如系统头文件 <stdio.h></stdio.h>),又想在 C++ 里显式强调链接方式,可以手动声明:
extern "C" {
#include <stdlib.h>
#include <string.h>
}
- 这种写法等价于把整个
#include块放进extern "C"作用域 - 不能对 C++ 标准库头文件(如
<iostream></iostream>)这么干 —— 它们内部已处理好兼容性 - 某些旧版 MinGW 或嵌入式工具链可能不支持
extern "C"套#include,此时应改用第一种头文件方式
extern "C" 不能修饰模板、重载函数和类成员
extern "C" 的本质是禁用 C++ 特性相关的符号生成规则,所以它和以下内容互斥:
- 模板函数:因为实例化后符号名仍需 mangling 来区分类型参数
- 重载函数:C 不支持同名多签名,链接器无法分辨哪个是你要的
foo(int)还是foo(double) - 类内函数、静态成员、构造/析构函数:它们依赖 C++ 对象模型,C 无法理解
this指针或 vtable 布局 - 返回或参数含 C++ 类型(如
std::string、std::vector<int></int>)的函数:C 端根本没法传参或接收
真正跨语言接口必须用纯 C 风格:只用 int、char*、struct(且不含虚函数/非 POD 成员)、指针、回调函数指针。










