本篇文章我们来讲解为什么C语言不支持函数重载,而C++可以支持,如果对函数重载的基本概念还不清楚,可以看一下我的上篇文章:C++入门前菜
在本文章中,我们需要搞懂两个问题:
1.C++是如何支持重载的?
2.为什么C语言不能支持?
首先,我们需要了解程序编译链接的过程(这里做大致介绍),我用一张图来大致描述编译链接的过程
- 其中,组成程序的所有源文件(也就是我们通常所说的
.c
,.cpp
文件)通过编译过程生成目标文件 - 每个目标文件由链接器(linker)捆绑在一起,组成一个单一的可执行程序
- 链接器在链接时也同时会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接在程序中
然后编译又可分为预编译,编译,汇编三个过程.
预编译:在预编译阶段,编译器大致会做:
- 头文件的展开
- 删除注释
- 条件编译
- 宏替换
生成test.i
文件
编译:在编译阶段,编译器会
- 将C语言代码转换成汇编代码(
test.s
)- 进行语法分析,词法分析,语义分析
- 符号汇总
汇编:在汇编阶段,编译器会把汇编代码转换成二进制指令(test.o
),形成符号表.
链接:在链接阶段,链接器会
- 合并段表
- 符号表的合并和重定位
- 找调用函数的地址,链接对应上,合并到一起
最终生成可执行文件test.exe
.
接下来,我们着重来看看C
语言和C++
在生成符号表这一过程中有什么不同?我会在Linux
系统中写代码并查看编译过程为大家演示:
🚀1.C语言为什么不能支持重载?
首先,我们创建了三个文件:
然后我们通过gcc -o mytest f.c test.c
来生成可执行文件mytest
,接着我们再用objdump -S mytest
命令就可以跳转来查看此程序生成的符号表.如图:
在图中,可以看见,当C语言在编译过程生成符号表时,它的函数在符号表中的名字就只是用自定义的函数名来表示,所以,如果在C语言中写了函数重载,那么它会在符号表中生成两个名字一模一样的函数名,那这样,在链接的过程中它的符号表中会有两个完全一样的函数名,那编译器怎么知道要去找哪个呢?
所以,这个时候就发生了错误.这也就是C语言不能支持重载的原因.
🪐2.C++为什么能够支持重载?
同样的,我们也来观察C++在编译过程中产生的符号表:
首先我们定义三个文件:f.cpp
, f.h
,test.cpp
然后我们通过objdump -S mytest
命令来查看符号表:
我们可以看到,在C++中,生成符号表时给函数的取名规则是-Z 函数名长度 函数名 参数类型首字母
,这样不同于C语言的取名方式,也就将发生函数重载的函数区别开来,这样,在链接过程中,编译器也就知道在符号表寻找函数时也就知道该去寻找哪一个对应的函数.
这也就是C语言为什么不能支持函数重载而C++却可以.