【C++深度剖析】为什么C++支持函数重载而C不支持--C++程序编译链接过程--符号表生成规则【Linux环境超详细解释C++函数重载底层原理】
前言
先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注我哦!️️️
这一篇的内容涉及C++
程序运行底层,我们需要对C++
程序的编译和链接过程要非常熟悉,我们才可以掌握这一篇的内容。在这里,博主先给大家安利一篇程序编译链接的干货文章。这里面的内容对大家的学习是非常有帮助的。
由于这篇文章的内容我们需要用Linux环境来进行演示,因此我们先要熟悉Linux的一些基本操作。
那么这里博主先安利一下一些干货满满的专栏啦!
数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏:算法 这里可以说是博主的刷题历程,里面总结了一些经典的力扣上的题目,和算法实现的总结,对考试和竞赛都是很有帮助的!
力扣刷题专栏:Leetcode 想要冲击ACM、蓝桥杯或者大学生程序设计竞赛的伙伴,这里面都是博主的刷题记录,希望对你们有帮助!
C的深度解剖专栏:C语言的深度解剖 想要深度学习C语言里面所蕴含的各种智慧,各种功能的底层实现的初学者们,相信这个专栏对你们会有帮助的!
Linux环境g++编译器的配置以及一些准备工作
如果要搞清楚C++支持重载的原因的本质,我们需要使用g++编译器来逐步编译源文件。
- gcc是C的编译器
- g++是C++的编译器
在我们安装Linux环境的时候,gcc一般是已经帮我们安装好了的,但是g++需要我们自己配置一下,输入一个指令即可
配置g++指令:yum install gcc-c++ libstdc++-devel
当然,这个指令需要root权限,我们在指令前加个sudo
,然后输入密码即可。
现在g++已经安装好了,使用方式和gcc大致相同,还没弄清楚的伙伴可以参考这篇,了解一下怎么逐步编译源文件。
准备工作:
准备三个源文件,func.h func.c test.c
(不会弄的先看看博主关于Linux基本指令的文章,先学会在Linux环境下编程)
.h
文件里面准备好两个相互重载的函数的声明
func.c
文件里面准备好这两个函数的定义
test.c
里面准备好函数的调用代码
注意:为什么我们写C++程序,后缀可以用.c,这是因为在Linux系统中,后缀其实不那么重要,辨识文件的其实是iNode,这个博主在往期博客里有讲,在文章开头有传送门。
无论我写成.c
还是.cpp
,只要我用gcc编译就是C语言,用g++编译就是C++。
源文件的符号表生成以及分析
在这里博主带大家复习一下,一个源文件到一个可执行程序(windows下为.exe,linux下为.out)
的过程。
那么为什么C++可以支持函数重载呢?其实就是在汇编过程生成符号表的时候,函数名修饰规则支持的!
现在,我们先把符号表找出来看看!我们看看func.c的符号表,这里涉及很多Linux的操作,博主还是继续提供传送门。
我们输入指令g++ test.c -c
和g++ func.c -c
来生成test.c
和func.c
所对应的汇编文件,test.o
和func.o
(用gcc编译会报错,因为C不支持重载)
我们用readelf
这个工具查看.o
文件的符号表。
用-s
选项选择查看符号表。(这些博主在传送门的文章里都有讲)
此时我们可以清晰的发现,两个名字相同的函数经过修饰之后,名字不同了。
_Z4funcid
_Z4funcii
其中4代表函数名的长度,id代表参数类型的首字母(ii同理)
这就是为什么在链接的时候不会有名字冲突的情况出现。
因为g++编译器也就是C++的编译器,在形成符号表的时候会对函数名进行修饰,而且修饰过后的名字和函数的参数有关!
现在我们换gcc(C的编译器)来尝试一下,看看符号表的函数名,还有没有这种修饰,当然,在此之前我们要调整一下源文件里面的内容,把重载函数去掉,否则会报错。
看到这里,相信大家已经可以清楚的了解到:C++支持函数重载的本质原因,其实就是生成符号表时的函数名修饰规则!
尾声
看到这里,我相信伙伴们对这个问题已经有了比较深入的了解了。
如果这篇博客对你有帮助,一定不要忘了点赞关注和收藏哦!