1、C++ 和 C 的符号修饰(Name Mangling)
C++编译器会对函数名称进行符号修饰(name mangling),以支持函数重载等特性。这种修饰会改变函数在目标代码中的名称,而C语言则不会进行这样的符号修饰。
#include<iostream>
using namespace std;
void foo(int a); // C++中的函数声明
int main() {
cout << "Hello, World!";
return 0;
}
在C++中,foo(int)
可能会被编译器修饰为 _Z3fooi
或类似的名字,以便区分不同的重载版本。C语言中,foo
会直接编译为符号 foo
,没有附加信息。
由于这种差异,C++编译器在链接C语言代码时无法找到对应的符号。extern "C"
命令告知C++编译器以C的方式处理指定代码块中的符号,避免符号修饰。
2、extern "C" 的用法
extern "C"
用于告诉编译器按照 C 语言的方式进行函数名修饰(即“C 语言链接”)。这对于需要与 C 代码进行交互的场景非常有用,因为 C++ 编译器通常会对函数名进行“名称修饰”(Name Mangling),而 C 语言则不会。使用 extern "C"
可以让 C++ 函数名在链接时符合 C 语言的格式,从而与 C 代码兼容。
1) 单个函数声明
如只想将一个单独的函数声明为 C 函数,可以直接使用 extern "C"
关键字,
#include <iostream>
// 使用 extern "C" 将 foo 函数按 C 的方式链接
extern "C" void foo(int a);
// foo 函数的定义
void foo(int a) {
std::cout << "Called foo with argument: " << a << std::endl;
}
int main() {
foo(42); // 调用 foo 函数
return 0;
}
2)多个函数声明(代码块)
在 extern "C"
代码块中声明两个函数 foo
和 bar
,然后在主函数中调用它们。
#include <iostream>
// 使用 extern "C" 代码块将多个函数声明为 C 链接方式
extern "C" {
void foo(int a);
void bar(double b);
}
// foo 函数的定义
void foo(int a) {
std::cout << "Called foo with integer argument: " << a << std::endl;
}
// bar 函数的定义
void bar(double b) {
std::cout << "Called bar with double argument: " << b << std::endl;
}
int main() {
foo(42); // 调用 foo 函数
bar(3.14); // 调用 bar 函数
return 0;
}
3、主要用途
1)链接C语言的库
C++项目经常需要调用C语言库,如标准库(math.h
)、POSIX库,或其他第三方C库。为了保证链接时C++编译器能够正确解析C函数的符号,需要在包含C库的头文件时使用 extern "C"
。
extern "C" {
#include <math.h>
}
int main() {
double result = sqrt(4.0);
return 0;
}
使用 extern "C"
保证了 sqrt
等标准C库函数的符号能够被正确解析。
2) 在C++中定义C接口
如在C++中编写的代码需要提供给C程序调用,可以使用 extern "C"
来定义C兼容的接口,使C代码可以调用这些C++函数。
#include <iostream>
// 使用 extern "C" 定义一个 C 兼容接口
extern "C" void c_interface();
void c_interface() {
// C++ 实现细节
std::cout << "This is a C-compatible interface with a C++ implementation." << std::endl;
}
int main() {
c_interface(); // 调用 C 兼容接口
return 0;
}
4、extern "C" 的注意事项
1)只能用于函数和变量声明
extern "C"
只能用于函数和变量的声明,不能用于类、模板、命名空间等C++特有的特性。
2)无重载支持
由于C语言不支持函数重载,使用 extern "C"
声明的函数不能重载。
3)头文件中使用 extern "C"
为了在C++中包含C头文件,通常在C库的头文件中使用条件编译,以便在C和C++代码中都能正常使用。