C++ - 了解Name Mangling
名字粉碎?命名粉碎?名称改编?
or 命名倾轧(实属拗口)?
函数重载
函数重载:
为方便使用,C++允许在同一范围内声明几个功能类似的同名函数,但是这些同名函数的形式参数(个数、类型、顺序)必须不同,也就是说用同一个函数完成不同的功能。
注:在C语言中,不支持函数的重载,即C语言中一个函数不能与另一个函数重名。重载原则:
①函数名相同,函数的参数列表不同(个数、类型、顺序);
②匹配原则1:严格匹配,找到再调用;
③匹配原则2:通过隐式类型转换寻求一个匹配,找到则调用;
④返回值类型不构成重载条件。
什么是 Name Mangling?
Name Mangling 是C++ 函数重载的底层实现原理 ;
被翻译成为:“名字粉碎”、“命名倾轧”;(用这个的人比较多,可能因为看起来比较晦涩、难懂,从而显得高大上?(瞎猜的)
);
以此来改名函数名,区分参数不同的同名函数。
Name Mangling 如何实现的?
通过查看符号表来举例:
- 我们先准备一个很简单的cpp文件(
test.cpp
):
- 接着g++编译它:
- 接着执行
objdump -t 目标文件
:
我们可以发现:
图中红框标出来的部分,即是命名倾轧的结果;
其中(以_Z3funi
举例):
①:_Z
是规定的前缀;
②:3
是函数名的字符个数(前面定义为fun
);
③:fun
是函数名;
④:i
是参数列表中类型 i 的首字母。
注:
不同系统和编译器的命名倾轧规则是不一样的。
如何禁用呢?
我们都知道,C++是从C语言的基础上发展而来的,既然C语言不支持函数重载,那么C++在调用C语言的时候可能就会出问题,问题的关键就在于这个函数重载,把它禁用了就好。
如何禁用呢?
使用声明:
extern "C"
的函数会禁止命名倾轧;
这样C++的函数就可以被C语言调用了。
通过查看一些C语言标准头文件,就可以发现其中有这个
extern "C"
,表示不倾轧调用时的函数名。
注:
为了头文件可以同时被C++/C使用,通常把extern "C"
放在__cplusplus
条件的宏定义中。
For example:
#include <iostream>
#include <string.h>
using namespace std;
extern "C"{
void func(int a){cout<<"a = "<<a<<endl;}
void func(int a,double b){cout<<"a = "<<a<<endl;}
}
int main(void){
int a = 10;
func(a);
return 0;
}
这样的代码是不能够编译通过的,因为不倾轧的话就会使得两个函数的函数名一样,产生了重名。要想让上述代码正常调用,必须使用命名倾轧,做法如下:
#include <iostream>
#include <string.h>
using namespace std;
//倾轧就不会重名
void func(int a){cout<<"a = "<<a<<endl;}
void func(int a,double b){cout<<"a = "<<a<<endl;}
int main(void){
int a = 10;
func(a);
return 0;
}
参考资料
【1】Sunrise. C++函数重载及原理(命名倾轧name mangling). CSDN. 2020-6-13
【2】Apollon_krj. C++函数重载与重载原理:命名倾轧. CSDN. 2017-03-07
【3】重载函数(百度百科)
TO BE CONTINUED…