C++调用C函数必须加extern "C",否则因名称修饰差异导致链接时符号不匹配而报undefined reference错误;需在C++中用extern "C"包裹头文件或函数声明,并确保C源文件参与编译链接。

函数声明必须加 extern "C"
直接在 C++ 里 #include 一个 C 头文件,然后调用里面的函数,大概率会链接失败,报类似 undefined reference to 'func_name' 的错误。这是因为 C++ 编译器默认对函数名做 name mangling(名字修饰),而 C 编译器不会——两者生成的符号名对不上。
解决办法是在 C++ 代码里声明该函数时,用 extern "C" 告诉编译器:“按 C 的方式处理这个符号”。常见写法是:
extern "C" {
#include "my_c_header.h"
}
或者只包裹单个函数声明:
extern "C" int my_c_function(int a, char* b);
注意:extern "C" 只影响链接符号,不改变调用约定(如 __cdecl),一般也不需要额外指定。
C 头文件本身要兼容 C++
很多纯 C 头文件没考虑 C++ 场景,直接 #include 进 C++ 项目可能报错,比如:
-
inline在 C99 和 C++ 中语义不同,C++ 编译器可能不认 C 风格的 inline 用法 -
restrict关键字在 C++ 标准里不存在(直到 C++20 才引入[[likely]]等,但不是 restrict) - 某些宏定义用了 C 特有语法(如
__attribute__在非 GCC/Clang 下可能未定义)
稳妥做法是在 C 头文件开头加保护:
#ifdef __cplusplus
extern "C" {
#endif
<p>// 正常的函数声明、类型定义等</p><h1>ifdef __cplusplus</h1><p>}</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h1>endif</h1>
这样头文件既能被 C 编译,也能被 C++ 安全包含。
链接时要确保 C 目标文件或库已参与构建
即使声明和头文件都对了,如果 C 源码没编译进项目,或者静态库没链接上,照样链接失败。常见疏漏点:
- C 源文件(如
utils.c)没加到 C++ 项目的 build list 里(例如 CMake 中忘了add_library或target_sources) - 用的是预编译的 C 静态库(
libutils.a),但链接命令没加-lutils,或没用-L/path/to/lib指定路径 - 混合使用 GCC 和 MSVC:GCC 编译的 C 对象不能直接给 MSVC 链接器用(ABI 不兼容)
验证是否链接成功,可以看最终可执行文件的符号表:nm -C your_executable | grep my_c_function(Linux/macOS);Windows 下可用 dumpbin /symbols。
参数和返回值类型要严格一致
C 和 C++ 对基础类型的大小和对齐通常一致(如 int、char*),但有些类型容易出问题:
-
bool:C 里没有原生bool(除非用_Bool或stdbool.h),而 C++ 的bool是独立类型,大小可能为 1 字节,但传递时若两边解释不一致会出错 - 结构体:如果 C 头文件里定义了 struct,在 C++ 里直接用没问题;但如果 C++ 侧重新定义了同名 struct(哪怕内容一样),就变成两个不兼容类型
- 函数指针:C 和 C++ 的函数指针类型不隐式转换,
void (*f)()和extern "C" void (*)()是不同类型
最安全的做法:所有跨语言接口只用 C 标准类型(int, size_t, char*, void*),避免 C++ 特有类型(std::string, class, template)出现在头文件中。
真正麻烦的从来不是加几行 extern "C",而是头文件没做 C++ 兼容、链接阶段漏掉目标文件、或者两边对某个 typedef 的理解不一致——这些地方一出错,错误信息往往很模糊,得一层层查符号和 ABI。
13万字C语言保姆级教程(深入):立即使用
在学习笔记中,你将探索c语言的核心概念和高级技巧!










