**编译器编译程序的过程**
假定程序员写出的3个文件:
func.h(函数声明)
func.c(定义函数)
test.c(main函数中使用函数)
1.预处理 -> 头文件展开、宏替换、条件编译、去掉注释
生成 func.i test.i
2.编译 -> 检查语法,生成汇编代码(仍然是给人看的一种语言)
生成 func.s test.s
3.汇编 -> 汇编代码转换为二进制机器代码
生成 func.o test.o
4.链接 -> 将.o文件链接在一起使用
生成a.out
编译时,如果遇到函数,就会在符号表(就是一块空间)里面先命名一个符号来存放函数的地址,.i文件是分开编译的,如果有多个.i文件会出现以下情况:
如果函数的使用在定义之前编译,无法在符号表里找到对应函数地址,则就先记为"?"(暂时未知),在全部编译结束后的链接过程将"?"在符号表里找到并替代为相应的函数地址,如果函数的定义在使用之前编译,则可以直接在符号表里面找到对应函数地址直接使用。
函数重载问题:
上面可以知道函数的使用是需要先在符号表里面命名一个特殊符号来存放函数的地址
C语言不支持函数重载,c语言的符号表中是以函数名为符号来储存函数地址,函数名相同的重载函数的地址应该不同,于是符号表中存在两个同符号的函数地址,在查找使用时会存在歧义和冲突
C++的符号表中的符号不是以函数名命名的,不同编译器储存方式不同,称为函数名修饰规则:
g++的函数名修饰规则: _Z + 函数名长度 + 函数名 + 参数类型首字母
(例如: f(12) -> _Z1fi; func(int a,int *p) -> _Z4funciPi)
有了函数名修饰规则,c++中重载函数所对应符号表中的符号就不同,查找时不存在歧义和冲突
在链接的时候,text.o中的"?"就使用相同的函数名修饰规则在符号表里面查找符号,查找到相同的符号就拿出相应的函数地址来代替
(注:链接是在.o文件的基础上进行,所以链接时使用的符号表是.o文件当中的,为了方便演示,上面的符号都是.s中程序员能看懂的符号名,汇编后的符号名就只有机器能看懂了)