链接 小结

如果没有ide,我们如何去编译两个关联的文件?

比如我在main.cpp中需要一个叫做add的函数,但是这个函数的定义我却放在了一个叫做add.cpp的文件中

那么我如何将两者关联?

这时就需要链接出场了

从一个普通文件------->可执行文件 一般需要四步
1.预处理
2.编译
3.汇编
4.链接

这里就可以发现,链接是发生在最后,当编译器和汇编器将代码转成ASCII汇编语言文件后,成为可重定位目标文件 .o后,就需要链接器发挥作用了

这里说明一下为了构造可执行文件,链接需要完成的两点
1.符号解析
2.重定位

那么我们还是要考虑如何关联两个文件,可是想到的是,如果两个文件需要关联,那么一定是文件A引用了文件B的某个函数,变量,那么链接器如果知道每个文件中所有函数名或者变量,那么我就可以确定A是否需要链接B

以此出发,我们明白了为什么可重定位目标文件都有一个符号表

这个符号表中都有目标m中定义或者引用的符号的信息,其中有三种不同的符号
1.允许被其他目标引用的全局符号
2.由其他目标定义并被m引用的全局符号
3.只被m定义和引用的局部符号-----------------static关键词---------加上static的函数还是变量都只在声明它的文件中可见

static可以更形象的理解成C++中的private,每个文件就是每个类,其中可以决定哪些数据公有还是私有

对于链接器来说,每个可重定义目标都有其符号表,如果符号表中的符号重复,那么该怎么办?

这里就触及了重载等知识,对于重载函数来说,其名称一样但是参数列表却不一样,对于链接器来说
xxx::a(int , long)
xxx::a(int)
在它眼中是 xxx__1ail 和xxx__1ai 这样表示的,所以肯定不存在重复

但是变量不同,如果两个文件有相同名称的全局变量,那么就要靠编译器来加一个条件来处理了

在编译时,编译器向汇编器输出每个全局符号,并将其定义为强符号或者是弱符号

函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号

并且定义规则:
1.不允许有多个同名的强符号
2.如果有一个强符号和多个弱符号同名,那么选择强符号
3.如果有多个弱符号同名,那么从任意一个弱符号中挑选一个

我们知道C++中提供很多函数,这些其实都是通过链接定义这些函数的文件实现的,这里可以通过让编译器去识别这些函数,但是这样如果需要更新某个函数,就需要去更新整个编译器;如果将所有的函数都放在一个可重定义目标模块中,那么每一个需要模板中某个函数的目标都需要去链接一份这个含有大多数函数的模块,这意味着在有限的内存中,每个程序都会运行这个模块的副本,这是对内存的极大浪费

所以大佬们提出了静态库概念,将函数编译为独立的可重定义目标模块,然后将所有模块封装成静态库,应用程序可以通过这个库来链接被程序引用的目标模块,这样不必因为更新某个函数而更新整个库,也不需要引用过多自己不需要的函数所在的模块

链接器从左到右扫描命令行出现的可重定位目标文件和存档文件
在扫描中,链接器维护了一个可重定位目标文件的集合E(最后的可执行文件就是E中文件的合并),一个引用了但是没有定义的符号集合U,一个在前面模块中已经呗定义的符号集合D
对于命令行中的每个文件f来说,链接器会判断f是一个目标文件还是存档文件。
如果f是个目标文件,那么链接器把f添加到E,并且通过f维护一下U和D

如果f是个存档文件,那么就直接维护U和D,例如对于f中的定义去比较U如果匹配,那么就将这个符号添加进D,并且将f添加进E

当完成所有文件的扫描后,如果U是非空的--------还有引用了但没有定义的符号,链接器就是输出一个错误,否则就合并E并生成一个可执行文件

完成了符号解析,也就意味着将模块间符号引用和定义关联了起来,此时就要开始进行重定义

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值