theme: channing-cyan highlight: a11y-dark
「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」
C 支持函数重载,即可以有多个同名但不同参数的函数。C 编译器在生成目标代码时如何区分不同的函数——它通过添加有关参数的信息来更改名称。这种向函数名称添加附加信息的技术称为Name Mangling。C 标准没有指定任何特定的名称修改技术,因此不同的编译器可能会向函数名称附加不同的信息。
考虑以下 Name Mangling 示例,其中包含函数f() 的各种声明 :
代码语言:javascript复制int f(void) { return 1; }
int f(int) { return 0; }
void g(void) { int i = f(), j = f(0); }
一些 C 编译器可能会将上述名称改写为以下名称,
代码语言:javascript复制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 程序。
代码语言:javascript复制#include <stdio.h>
int printf(const char* format, ...);
int main()
{
printf("haiyong");
return 0;
}
上述程序产生错误。
解释: 编译错误的原因很简单,c 编译器修改了printf() 的名字,没有找到新名字的函数定义。
解决方案: C 中的 Extern “C”
当一些代码被放入 extern “C” 块时,C 编译器确保函数名是未修改的——编译器发出一个名称不变的二进制文件,就像 C 编译器会做的那样。
如果我们把上面的程序改成下面这样,程序就可以正常工作并在控制台上打印“haiyong”(如下所示)。
代码语言:javascript复制#include <bits/stdc .h>
using namespace std;
extern "C" {
int printf(const char* format, ...);
}
int main()
{
printf("haiyong");
return 0;
}
输出
代码语言:javascript复制haiyong
因此,所有 C 风格的头文件(stdio.h、string.h 等)在 extern “C”块中都有它们的声明。
代码语言:javascript复制#ifdef __cplusplus
extern "C" {
#endif
// Declarations of this file
#ifdef __cplusplus
}
#endif
以下是上面讨论的要点:
1. 由于 C 支持函数重载,因此必须在函数名称中添加附加信息(称为 Name mangling)以避免二进制代码中的冲突。 2. C 中不能更改函数名称,因为它不支持函数重载。为了避免链接问题,C 支持 extern “C” 块。C 编译器确保 extern “C” 块内的名称不会更改。
如果您发现任何不正确的内容,或者您想分享有关上述主题的更多信息,请发表评论。