C++相较于C语言来说,重载是一重大特性,让我们一起简单的回顾一下重载那些事
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能相似的同名函数
这些同名函数的形参列表(参数个数or类型or顺序)必须不同
通常用来处理功能类似数据类似的场景,简而言之,为方便使用.
或者说发明C++的大佬们在没有C++使用C语言编程时日积月累的经验吧()
我们常说C++是C语言的超集,是兼容C语言的一门高级编程语言.那我们有没有想过这么一个问题:为什么C++支持函数重载,而C语言不支持函数重载?
这也是写这篇文章的目的所在
在C和C++中,应该程序要运行起来,要经历:预处理、编译、汇编、链接
下面我们借助Linux中gcc来理解一下这些过程
首先我们在Linux下创建以下文件
注: .cc也是cpp文件
这里采用了VScode远端连接的方法编辑(防止有人问为什么不像vim或者nano)
Linux下,gcc是C语言的编译器,g++是C++的编译器
以下是一个简单的运行方法(看不懂的家人可以跳过,不是重点)
首先
预处理的工作大致有 头文件展开、宏替换、条件编译、去掉注释.
即代码层面上的处理后,只保留需要执行的部分.产生后缀为**.i**预处理文件.
编译大致有检查语法,生成汇编代码.由**.i文件产生后缀为.s**汇编文件.
(像这样)
汇编即把像上图一样的汇编代码转化成二进制的机器码供CPU读取.由**.s文件生成.o**后缀的目标文件.
链接找到调用函数的地址并链接对应,合并到一起
我们首先要大致明白,函数在调用时,汇编代码中都会有一个call指令来叫一下这个函数的地址
这里又牵扯到了符号表
链接时就会查询符号表,符号表里记录了函数与其地址的映射关系,即可以通过call地址的方式来找到函数并调用,但vs中的汇编代码经过修饰,展示并不直观
我们借助Linux查看一下程序运行产生的符号标识
我们找到了一些特定标识,其实这些就可以看作是符号表内函数地址与函数名,且与代码对应.
我们仔细观察可以发现,每个函数,严格一点我们称之为重载函数之间地址是不相同的,他们的函数名也不相同.
他们的命名好像存在一种规则,有函数名的同时参数类型的首字符存在于函数名中!!!
每个平台下规则不同,规则问题不用纠结
至少在这里,是**_Z 函数名长度 函数名 类型首字母**(指正类型会加一个i,如int* 即 ii)
这是不是意味着,重载函数的参数顺序不同,类型不同,个数不同,就意味着编译器底层会对其生产一个独一无二的单独的函数名和不同的地址,可以认为从根本意义是他们不是同一个函数(可以这样理解).
然后来观察一下C语言
显而易见的,底层并没有对名称进行修饰!!!
C++的编译器会将函数名在底层进行修饰,形成独一无二的名称与地址,从而实现函数重载,但是C语言没有.
所以C++支持函数重载,但C语言不支持.
编译器底层将C++的函数名进行了修饰,C语言在查询符号表时找不到函数.反之亦然
编译器底层没有将C语言的函数名进行修饰,C++在查询符号表时找不到函数
解决方法:extern “c”,通常借助宏判断.