extern "c"用于禁用c++名称修饰,使符号按c规则生成;需用#ifdef __cplusplus条件包裹头文件,声明与定义必须一致,且块内不可使用c++特性。

extern "C" 是用来禁用 C++ 名称修饰的声明
它告诉 C++ 编译器:这部分函数或变量的符号名要按 C 的规则生成,不加参数类型、命名空间等修饰。否则 C++ 编译出的 _Z1fii 这类符号,C 代码根本找不到。
常见错误现象:undefined reference to 'foo'(链接时找不到),明明 C 文件里写了 void foo(int);,C++ 里也声明了,但就是连不上——大概率是 C++ 端没加 extern "C"。
- 只对函数声明和变量声明有效,不能用于类、模板、内联函数
- 必须出现在 C++ 代码中(C 文件里写这个会编译报错)
- 如果头文件要同时被 C 和 C++ 包含,得用
#ifdef __cplusplus包一层
混编头文件的标准写法:__cplusplus 宏判断
这是最常被漏掉的一环。直接在头文件里写 extern "C",C 编译器会懵;不写,C++ 又修饰符号。唯一稳妥方式是条件包裹:
#ifdef __cplusplus
extern "C" {
#endif
void do_work(int x);
int get_value(void);
#ifdef __cplusplus
}
#endif
使用场景:封装 C 库供 C++ 调用,或把 C++ 实现的底层模块暴露给 C 上层调用。注意:C 无法理解 std::string 或引用参数,接口里只能用 C 兼容类型(int、char*、struct 等)。
立即学习“C++免费学习笔记(深入)”;
本文档主要讲述的是Android JNI开发入门与提高;JNI在Android系统中有着广泛的应用。Android系统底层都是C/C++实现的,上层提供的API都是Java的,Java通过JNI调用底层的实现。比如:Android API多媒体接口MediaPlayer类,其实底层通过JNI调用libmedia库。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
extern "C" 块内不能出现 C++ 特性
一旦进了 extern "C" 块,就退回 C 语义环境。下面这些都会报错:
-
std::vector<int></int>作为参数或返回值 - 重载函数(
void f(int)和void f(double)不能共存于同一extern "C"块) - 带默认参数的函数声明(C 不支持)
- 类成员函数(哪怕是 static 的,也不能放进去)
性能/兼容性影响:无运行时开销,纯编译期行为;但若误把 C++ 类型塞进去,编译直接失败,不是警告。
链接时符号不匹配的快速自查方法
当遇到 undefined reference,别急着改代码,先看符号长啥样:
- 用
nm -C libxxx.a | grep foo(-C表示 demangle)看 C++ 目标文件里导出的是不是foo(int) - 用
nm libxxx.a | grep foo(不加-C)看实际符号名,如果是_Z3fooi就说明没生效 - C 对象文件里用
nm xxx.o查,应该看到简单的foo
容易被忽略的是:C++ 源文件里声明了 extern "C",但对应实现(.cpp)里忘了加——声明和定义必须一致,否则链接器看到两个不同修饰的 foo,依然报错。







