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++代码中都能正常使用。