编译流程分为四个阶段:预处理、编译、汇编、链接
以Linux系统下g++编译为例:
通过g++的选项可以查看过程中的每一步
预处理:处理一些#号定义的命令或语句(如#define、#include、#ifdef等),生成.i文件
编译:进行词法分析、语法分析和语义分析等,生成.s的汇编文件
汇编:将对应的汇编指令翻译成机器指令,生成二进制.o目标文件
链接:链接分为两种
静态链接
在链接期,将静态链接库中的内容直接装填到可执行程序中。
在程序执行时,这些代码都会被装入该进程的虚拟地址空间中。
动态链接
在链接期,只在可执行程序中记录与动态链接库中共享对象的映射信息。
在程序执行时,动态链接库的全部内容被映射到该进程的虚拟地址空间。其本质就是将链接的过程推迟到运行时处理
扩展:
01 为什么要有静态链接?
在我们的实际开发中,不可能将所有代码放在一个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如一个源文件可能要调用另一个源文件中定义的函数,但是每个源文件都是独立编译的,即每个.c文件会形成一个.o文件,为了满足前面说的依赖关系,则需要将这些源文件产生的目标文件进行链接,从而形成一个可以执行的程序。这个链接的过程就是静态链接
由很多目标文件进行链接形成的是静态库,反之静态库也可以简单地看成是一组目标文件的集合,即很多目标文件经过压缩打包后形成的一个文件
02 静态链接的优缺点缺点:
浪费空间,因为每个可执行程序中对所有需要的目标文件都要有一份副本,如果运行多个程序并且这些程序都对同一个目标文件有依赖,那么目标文件在内存中就会存在多个副本;
更新困难,因为每当一个依赖文件的代码修改了,这个时候就需要全部重新编译链接形成新的可执行程序。
优点:
运行速度快并且不依赖外部环境,因为在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。
注意:我们知道,链接器在链接静态链接库的时候是以目标文件为单位的。比如我们引用了静态库中的printf()函数,那么链接器就会把库中包含printf()函数的那个目标文件链接进来,如果很多函数都放在一个目标文件中,很可能很多没用的函数都被一起链接进了输出结果中。由于运行库有成百上千个函数,数量非常庞大,每个函数独立地放在一个目标文件中可以尽量减少空间的浪费,那些没有被用到的目标文件就不要链接到最终的输出文件中。
03 为什么要有动态链接?
为了解决静态链接中提到的两个问题,一方面是空间浪费,另外一方面是更新困难。
流程简介:
假设现在有两个程序program1.o和program2.o,这两者共用同一个库lib.o,假设首先运行程序program1,系统首先加载program1.o,当系统发现program1.o中用到了lib.o,即program1.o依赖于lib.o,那么系统接着加载lib.o,如果program1.o和lib.o还依赖于其他目标文件,则依次全部加载到内存中。当program2运行时,同样的加载program2.o,然后发现program2.o依赖于lib.o,但是此时lib.o已经存在于内存中,这个时候就不再进行重新加载,而是将内存中已经存在的lib.o映射到program2的虚拟地址空间中,从而进行链接.
04 动态链接的优缺点优点:
节约内存:即使需要每个程序都依赖同一个库,但是该库不会像静态链接那样在内存中存在多分,副本,而是这多个程序在执行时共享同一份副本;
更新方便:更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标。
缺点:
性能略差:因为把链接推迟到了程序运行时,所以每次执行程序都需要进行链接,所以性能会有一定损失。
依赖外部环境:因为把链接推迟到了程序运行时,所以要保证程序运行时外部的库存在且内容正确无误。
审核编辑:郭婷
-
Linux
+关注
关注
87文章
11292浏览量
209315 -
C++
+关注
关注
22文章
2108浏览量
73617
原文标题:C/C++的编译流程?
文章出处:【微信号:嵌入式学习站,微信公众号:嵌入式学习站】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论