前言
本文总结学习C++小白篇—01函数重载的原理。
函数重载的原理
为什么C++支持函数重载,而C语言不支持
1.1 程序编译链接的原理
一个程序需要运行起来,需要经历:编译和链接两阶段。其中编译又可以具体分为预处理、编译、汇编
- 预处理阶段:将各个源.c文件单独处理,头文件的展开、条件编译、删除注释、宏替换,生成.i文件;
- 编译阶段:将各个.i文件单独处理,语法分析、词法分析、语义分析、符号汇总,把C/C++语言代码转换成汇编代码,生成.s文件
- 汇编阶段:将各个.s文件单独处理,把汇编代码转换成二进制指令,生成.o文件
- 链接阶段:将所有.o文件和链接库一起链接,主要进行:合并段表、符号表的合并和符号表的重定位,生成可执行文件。
1.2 结合函数重载分析
假设我们创建三个文件:
- 头文件f.h:函数f的声明
- 源文件f.c:包含头文件f.h,函数f的定义(void f(int num, char c))
- 源文件test.c:包含头文件f.h,调用函数f
1.2.1 预处理阶段
分别单独将源文件f.c 和 test.c进行:
- 头文件f.h的展开
生成文件f.i 和 test.i
1.2.2 编译阶段
分别单独将文件f.i 和 test.i进行:
- 把C/C++语言代码转换成汇编代码
文件f.i中,函数f变成了函数的各个指令
·
文件test.i中,因为该单独文件内没有函数f定义,只有声明,语法可以通过,但是该调用指令转变的汇编代码为:函数名(0X000…),不知道函数f的具体地址,赋为默认地址0X000…,等链接阶段,合并符号表时,会通过编译器对自己的函数名修饰规则的汇编代码中的函数名,来找对应该函数名的地址,然后链接在一起
- 符号汇总
- 检查语法:
1-f.i文件中:检查声明和定义是否匹配
2-test.i文件中:检查声明和函数调用是否匹配
注!!!
缺省参数必须在声明给,不能再定义给:
因为在编译阶段,在test.i文件中:检查声明和函数调用是否匹配时,如果声明未给缺省参数,且调用时使用缺省参数,则编译不通过。
生成文件f.s 和 test.s
1.2.3 汇编阶段
分别单独将文件f.s 和 test.s进行:
- 把汇编代码转换成二进制指令
生成文件f.o 和 test.o(f.obj 和 test.obj)
1.2.4 链接阶段
整体将文件f.o 和 test.o(f.obj 和 test.obj)和链接库进行:
- 合并段表
- 符号表的合并
- 符号表的重定位
文件test.o中生成的指令未包括函数f的地址,在此就在所有合并在一起的.o文件中,一个一个.o文件中找该函数名(编译器对自己的函数名修饰规则的汇编代码中的函数名)的地址,如果找到就链接到一起。
注:如果在f.c文件中不放函数f的定义,则链接时,在各个.o
文件无法找到函数f的真正地址,只有之前的默认地址(或没有地址),从而报错:链接错误。
生成可执行文件
1.3 函数重载的原理
- 在C语言编译器下:编译阶段将C代码转为汇编代码时,汇编代码的函数名就是原本C代码的函数名,本例中就是f
- 在C++语言编译器下:编译阶段将C代码转为汇编代码时,汇编代码的函数名是特殊规则形成的,如果在linux下g++编译器下,汇编代码下函数命名规则为:
_Z 函数名长度 函数名 参数类型首字母
本例中就是_Z1fic
所以!!!
函数重载的原理就是:
C++编译器下,在编译阶段形成汇编代码时,函数名的汇编代码会根据特殊规则定义,而该特殊规则下:满足在函数重载的三种类型:1-参数个数不同;2-参数类型不同;3-参数类型的顺序不同下,函数名的汇编代码都不同,从而在链接阶段各自用不同的汇编函数名,去链接,匹配地址,不会出错。
而C语言下,显而易见,会报错。
总结
这里对文章进行总结:
以上就是今天总结的内容,本文包括了函数重载的原理,分享给大家。
真💙欢迎各位给予我更好的建议,欢迎访问!!!小编创作不易,觉得有用可以一键三连哦,感谢大家。peace
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。
欢迎各位大佬批评建议,分享更好的方法!!!🙊🙊🙊