前言
在c语言中,函数名是不可以重复的,在同一作用域中函数名称都是唯一的。这也使得我们的函数调用充满了种种麻烦。
而c++则支持通过函数重载解决了这个问题
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
C++为什么支持函数重载
为什么c语言不支持函数重载而c++能支持呢?
想要解释这个问题要先从编译链接说起
以以下代码举例
//fanc.h
#include<stdio.h>
int fanc(int i ,double d);
int fanc(int i ,int d);
//fanc.cpp
#include"fanc.h"
int fanc(int i,double d)
{
printf("fanc(int double)\n");
}
int fanc(int i,int d)
{
printf("fanc(int i)\n");
}
//main.c
#include"fanc.h"
int main()
{
fanc(1,1.1);
fanc(1,1);
return 0;
}
编译链接
以上三个文件变成可以执行文件需要经历以下步骤
以gcc编译器为例
预处理:
在预处理阶段,gcc会对源文件进行预处理操作。预处理器根据预处理指令(例如#include和#define等)对源代码进行处理。
预处理器的主要任务包括:
展开宏定义:
- 将代码中的宏展开为其定义的内容。
- 处理条件编译指令:根据条件编译指令(例如#ifdef和#ifndef)来控制代码的编译。 删除注释:删除源代码中的注释部分。
- 处理包含文件(#include):将包含的头文件插入到源代码中的对应位置。 处理其他预处理指令:例如#error、#pragma等。
预处理后的文件称为预处理文件,通常以.i作为扩展名。
编译:
在编译阶段,gcc将预处理文件(也可以是源文件)转化为汇编语言代码。
编译器会对代码进行语法和语义检查,并将代码翻译为汇编语言的表示形式。
编译阶段的主要任务包括:
- 语法检查:检查源代码是否符合语法规范。
- 语义检查:检查变量类型、函数调用以及其他语义错误。
- 生成汇编代码:将输入的源代码转换为汇编代码。
编译生成的文件称为汇编文件,通常以.s作为扩展名。
汇编:
汇编阶段使用汇编器将汇编代码转换为机器码指令,生成目标文件(Object File)。
汇编器会将汇编代码根据汇编语言的规则转换为与特定处理器架构兼容的机器指令。
汇编阶段的主要任务包括:
- 将汇编代码转换为机器码指令。
- 生成符号和调试信息。
- 汇编生成的文件称为目标文件,通常以.o作为扩展名。
链接:
在链接阶段,连接器将目标文件与所需的库文件进行链接,生成最终的可执行文件(Executable File)。
链接器的主要任务包括:
- 符号解析:解析目标文件和库文件中的符号引用和定义,将符号引用与定义进行匹配。
- -符号重定位:将目标文件中的地址信息重新定位,以便正确执行。
- 生成可执行文件:将符号解析和重定位后的目标文件链接在一起,生成可执行文件。
最终生成的可执行文件通常不包含源代码,可以直接在操作系统中运行。
c语言不能实现函数重载的原因就在于链接这一步
在汇编过程中函数会生成符号表
编译阶段的符号表包含了当前源代码文件中定义的变量、函数和其他标识符的信息。每个源文件编译时会生成自己的符号表。编译器将源代码转换为机器代码,并将符号引用替换为相应的地址或偏移量。
链接阶段的符号表则用于解析不同目标文件之间的符号引用关系。链接器负责将多个目标文件合并成一个可执行文件或库文件。在链接过程中,链接器会合并各个目标文件中的符号表,检查并解决符号的定义和引用之间的关联。
在合并符号表时,链接器执行以下操作:
- 符号解析:链接器遍历所有目标文件的符号表,将每个符号引用与一个符号定义关联起来。如果找不到符号的定义,链接器会报错。
- 符号合并:如果多个目标文件中有相同名称的符号,链接器将尝试将它们合并为一个符号。这通常用于解决多个目标文件中的全局变量和函数名冲突的情况。
- 重定位:在确定每个符号的最终内存位置后,链接器会更新引用该符号的指令或数据的地址。这涉及到修正相对地址或偏移量,以便正确地访问符号的定义。
- 通过符号表的合并和重定位,链接器确保在最终生成的可执行文件或库文件中,所有的符号引用都能正确地关联到符号定义的内存位置上。
c++函数名在符号表中是经过修饰的,通过函数名,参数种类,参数数目
共同命名,而c语言在符号表中的命名只和函数名有关。
当出现函数重载时,编译器无法分布两个函数的区别
简单来说:
c++在进行链接的时候,符号表中的函数名会根据参数名发生变化,而c语言只通过函数名命名
综上所述,可以发现一个问题
c++与c语言 在符号表中函数的命名存在差异
当两个语言的文件混合使用时,难免会出现一些问题
可以通过extern “C”来处理
extern “C”
在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。