在C++中命名Mangling和extern“C

「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

C++ 支持函数重载,即可以有多个同名但不同参数的函数。C++ 编译器在生成目标代码时如何区分不同的函数——它通过添加有关参数的信息来更改名称。这种向函数名称添加附加信息的技术称为Name Mangling。C++ 标准没有指定任何特定的名称修改技术,因此不同的编译器可能会向函数名称附加不同的信息。 

考虑以下 Name Mangling 示例,其中包含函数f() 的各种声明

int f(void) { return 1; }
int f(int) { return 0; }
void g(void) { int i = f(), j = f(0); }
复制代码

一些 C++ 编译器可能会将上述名称改写为以下名称,

int __f_v(void) { return 1; }
int __f_i(int) { return 0; }
void __g_v(void) { int i = __f_v(), j = __f_i(0); }
复制代码

注意:  C 不支持函数重载,因此,当我们在 C++ 中链接 C 代码时,我们必须确保符号的名称不被更改。

从 C++ 链接时如何处理 C 符号? 

在 C 中,名称可能不会被修改,因为它不支持函数重载。那么当我们在 C++ 中链接 C 代码时,如何确保符号的名称不被更改。例如,请参阅以下使用 C 的 printf() 函数的 C++ 程序。 

#include <stdio.h>
int printf(const char* format, ...);

int main()
{
	printf("haiyong");
	return 0;
}
复制代码

上述程序产生错误。

解释: 编译错误的原因很简单,c++编译器修改了printf() 的名字,没有找到新名字的函数定义。

解决方案:  C++ 中的 Extern “C”

当一些代码被放入 extern “C” 块时,C++ 编译器确保函数名是未修改的——编译器发出一个名称不变的二进制文件,就像 C 编译器会做的那样。

如果我们把上面的程序改成下面这样,程序就可以正常工作并在控制台上打印“haiyong”(如下所示)。

#include <bits/stdc++.h>
using namespace std;

extern "C" {
int printf(const char* format, ...);
}

int main()
{
	printf("haiyong");
	return 0;
}
复制代码

输出

haiyong
复制代码

因此,所有 C 风格的头文件(stdio.h、string.h 等)在 extern “C”块中都有它们的声明。

#ifdef __cplusplus
extern "C" {
#endif
// Declarations of this file
#ifdef __cplusplus
}
#endif
复制代码

以下是上面讨论的要点: 

1. 由于 C++ 支持函数重载,因此必须在函数名称中添加附加信息(称为 Name mangling)以避免二进制代码中的冲突。 
2.  C 中不能更改函数名称,因为它不支持函数重载。为了避免链接问题,C++ 支持 extern “C” 块。C++ 编译器确保 extern “C” 块内的名称不会更改。

如果您发现任何不正确的内容,或者您​​想分享有关上述主题的更多信息,请发表评论。