extern 关键字
如何加载其他模块的全局变量? extern关键字
如何解决C++与C混合编译问题? extern “C”
extern关键字
声明与定义
根据C++标准的规定,一个变量声明必须同时满足两个条件,否则就是定义:
声明必须使用extern关键字;
不能给变量赋初值
1 | int a; //定义 |
使用其他模块变量例子
1 | //file.h |
终端上编译运行,输出
1 | gcc main.cpp file.cpp && ./a.out |
这等同于
1 | //file.cpp |
如果不佳extern关键字将提示变量重复声明。
最佳实践
- h文件extern声明
- c/cpp文件内定义
- 使用时include头文件
extern “C”
extern "C" 是 C++ 中的一个关键字组合,用于解决 C++ 和 C 代码混合编程时的 名称修饰(Name Mangling) 和 链接兼容性 问题。它的核心作用是告诉 C++ 编译器:按 C 语言的规则处理函数名和链接方式,确保 C++ 代码可以正确调用 C 库函数,或者让 C 代码能调用 C++ 函数。
为什么需要这个关键字
知识点:C++与C的函数名称修饰规则不同
C++ 支持函数重载,编译器会对函数名进行修饰(例如 func(int) 可能变成 _Z4funci),以区分不同参数类型的同名函数。C 语言没有重载,函数名在编译后保持不变(例如 func 依然是 func)。如果 C++ 直接调用 C 库函数(或反过来),由于名称修饰差异,链接器会找不到符号,导致错误。
作用
- 禁用名称修饰
强制函数名按 C 语言的规则生成,保持简单名称。 - 确保二进制兼容性
使 C++ 编译后的函数符号与 C 库的符号一致,从而正确链接。
用法
(1) C++ 调用 C 函数
假设有一个 C 库 libfoo.c:
1 | // libfoo.c |
编译为 C 库:
1 | gcc -c libfoo.c -o libfoo.o |
在 C++ 中调用时,需要用 extern "C" 声明:
1 | // main.cpp |
编译链接:
1 | g++ main.cpp libfoo.o -o program |
(2) C 调用 C++ 函数
若要在 C 中调用 C++ 函数,需在 C++ 代码中用 extern "C" 导出函数:
1 | // libbar.cpp |
在 C 中声明:
1 | // main.c |
编译链接:
1 | g++ -c libbar.cpp -o libbar.o |
应用场景
调用 C 标准库函数
如<stdio.h>中的printf在 C++ 中通过extern "C"声明。使用第三方 C 库
例如 OpenSSL、SQLite 等 C 库的头文件通常包含extern "C"保护:1
2
3
4
5
6
7
8
9
extern "C" {
void c_library_function();
}导出 C++ 函数供 C 调用
在编写 C++ 动态库(.so/.dll)时,需用extern "C"导出接口。
总结
| 场景 | 解决方案 |
|---|---|
| C++ 调用 C 函数 | 用 extern "C" 声明 C 函数 |
| C 调用 C++ 函数 | 用 extern "C" 定义 C++ 函数 |
| 头文件兼容 C/C++ | 通过 #ifdef __cplusplus 包裹 |
仅适用于全局函数 :extern "C" 不能用于类成员函数或重载函数(因为 C 不支持这些特性)。