extern "C"
是 C++ 中用于与 C 语言进行互操作的重要关键字。它主要用于告诉编译器在链接阶段如何处理函数或变量名。下面是详细介绍 extern "C"
的背景、用途、以及使用方法:
# 1. 背景:
- 在 C 和 C++ 中,函数和变量的符号是通过名字来链接的,但 C++ 使用了 "名字修饰"(Name Mangling)来支持函数重载等特性。这种修饰会导致编译器生成的函数名不再是原始的函数名,而是带有类名、参数类型等信息的复杂字符串。
- 例如,C++ 中一个函数
int add(int, int)
可能会被编译器修饰成_Z3addii
或其他复杂的符号,而 C 语言中相同的函数名则是简单的add
。 - 由于 C 语言不支持函数重载和名字修饰,如果在 C++ 代码中直接调用 C 语言的函数,编译器会找不到匹配的符号,导致链接错误。
# 2. extern "C"
的用途:
- 消除名字修饰:
extern "C"
告诉编译器不要对函数进行名字修饰,而是保持 C 语言的链接方式,这样 C++ 代码就能正确链接 C 语言代码中的符号。 - 函数声明:
当在 C++ 中声明 C 语言函数时使用extern "C"
,以确保链接器找到正确的函数符号。 - 用于 C++ 与 C 语言混合编程:
尤其是在大型项目或跨语言项目中,经常需要 C++ 调用 C 语言的库,或者反过来,这时就需要extern "C"
来管理符号。
# 3. 使用方法:
单个函数声明:
1
2// 这是在 C++ 代码中声明一个 C 语言的函数
extern "C" void myCFunction(int arg);
这样做会告诉编译器myCFunction
是一个 C 语言函数,编译器将不会对它的名字进行修饰。多函数声明:
1
2
3
4extern "C" {
void func1(int);
int func2(double);
}
使用大括号可以一次性声明多个 C 函数,使它们都以 C 语言的链接方式处理。C 语言头文件的引用:
1
2
3
4
5// C 语言头文件可能没有使用 extern "C"
// 需要在 C++ 代码中做处理
extern "C" {
}
这确保了所有在my_c_library.h
中声明的函数在 C++ 中被正确识别为 C 语言函数。
# 4. 注意事项:
- 对变量的作用:
extern "C"
也可以用于变量声明,确保变量名在链接时不被修饰。 - 不能用于类:
由于 C 语言不支持类,因此不能对类使用extern "C"
。 - 多次声明:
在多个地方对同一函数使用extern "C"
是安全的,但在定义时需要确保只有一个链接的定义。 - 与 C++ 函数混合:
extern "C"
不能消除 C++ 特性,比如函数重载、默认参数等。这些特性在 C 语言中是不支持的。
# 5. 示例:
- 假设有一个 C 语言函数实现如下:
1
2
3
4
5
6// my_functions.c
void greet(const char* name) {
printf("Hello, %s!\n", name);
} - 在 C++ 中调用这个函数:
1
2
3
4
5
6
7
8
9// main.cpp
extern "C" {
void greet(const char* name);
}
int main() {
greet("World");
return 0;
} - 这段代码编译时不会出现链接错误,因为
greet
函数在 C++ 中被正确识别为 C 语言函数。
extern "C"
是在 C++ 和 C 混合编程中不可或缺的工具,确保了两种语言可以无缝协作。