对于C++源文件,从文本到可执行文件一般需要四个过程:预处理阶段→编译阶段→汇编阶段→链接阶段。
预处理阶段:对源代码文件中文件包含关系(头文件)、预编译语句(宏定义)进行分析和替换,主要是处理源代码文件中以"#"开头的预编译指令,生成预编译文件。规则如下:
(1)删除所有的#define,展开所有的宏定义。
(2)处理所有的条件预编译指令,如"#if"、"#endif"、"#ifdef"、"#elif"和"#else"。
(3)处理"#include"预编译指令,将文件内容替换到它的位置,这个过程是递归进行的,文件中包含其他文件。
(4)删除所有的注释,"//"和"/**/"。
(5)保留所有的"#pragma"编译器指令,编译器需要用到他们,如:"#pragma once"是为了防止有文件被重复引用。
(6)添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告时能够显示行号。
编译阶段:将经过预处理后的预编译文件转换成特定的汇编代码,生成汇编文件。即将.i或者.ii文件进行一系列的此法分析、语法分析、语义分析及优化后,生成相应的汇编代码文件。
(1)词法分析:利用类似于“有限状态机”算法,将源代码程序输入到扫描机中,将其中的字符序列分割成一系列的记号。
(2)语法分析:语法分析器对由扫描器产生的记号进行语法分析,产生语法树。由语法分析器输出的语法树是一种以表达式为节点的树。
(3)语义分析:语法分析器只是完成了对表达式语法层面的分析,语义分析器则对表达式是否有意义进行判断,其分析的语义是静态语义——在编译期能分期的语义,相对应的动态语义是在运行期才能确定的语义。
(4)优化:源代码级别的一个优化过程。
(5)目标代码生成:由代码生成器将中间代码转换成目标机器代码,生成一系列的代码序列——汇编语言表示。
(6)目标代码优化:目标代码优化器上对上述的目标机器代码进行优化,寻找合适的寻址方式,使用唯一来替代乘法运算、删多余的指令等。
汇编阶段:将编译阶段生成的汇编文件转换成机器码,生成可重定位目标文件。汇编器的汇编过程相对于编译器来说更简单,没有复杂的语法,也没有语义,更不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译过来,汇编过程由汇编器完成。经过汇编之后,产生目标文件.o(Windows下)或.obj(Linux下)。
链接阶段:将多个目标文件即所需要的库链接成最终的可执行目标文件。链接分为静态链接和动态链接。
(1)静态链接:函数和数据被编译进一个二进制文件。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件。这样做的特点是:空间浪费。因为每个可执行程序中对所有需要的目标文件都要有一份副本,所以如果多个程序对同一个目标文件都有依赖,会出现同一个目标文件都在内存中存在多个副本。更新困难。每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。运行速度快。在可执行程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。
(2)动态链接:动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是像静态链接库一样把所有程序模块都链接成一个单独的可执行文件。这样做的特点是:更新方便。更新时只需要替换原来的目标文件,而无需将所有的程序再重新链接一遍。当程序下一次运行时,新版本的目标文件会被自动加载到内存并且链接起来,程序就完成了升级的目标。性能损耗。因为把链接推迟到了程序运行时,所以每次执行程序都需要进行链接,所以性能会有一定损耗。共享库就是即使需要每个程序都依赖于同一个库,但是该库不会像静态链接那样在内存中存在多份副本,而是这些多个程序在执行时共享同一份副本。
更多关于动态链接库和静态链接库的特点与创建及使用,请访问:
https://blog.csdn.net/jiaomubai/article/details/89324115
https://blog.csdn.net/jiaomubai/article/details/89317432
总结一下动态链接库和静态库的区别就是:静态链接库是把所有的代码和数据都复制到本模块中,运行时就不需要库了。而动态链接库就是只建立一个引用的接口,真正的代码和数据存放在另外的可执行的模块中,在运行时再装入程序中。