欢迎大家学习更多知识!
编译和链接:
1.翻译环境和运行环境
在c语言实现的环境中,存在两个不同的环境.
翻译环境:在这个环境中源代码被转换为可执行的机器指令(二进制指令)
执行环境:执行实际代码.
eg:我们在编写代码时创建了test.c / add.c / max.c 等源文件,对于电脑他是无法读懂我们编写的代码,所以我们的代码需要经过这两个环境变化生成可执行程序.
2.翻译环境
根据上图我们的源程序经过翻译环境中怎么转换为可执行程序的呢?
翻译环境是由编译和链接两大过程组成,对于编译又分成:预处理(有些书也叫预编
译)、编译、汇编三个过程。
![](https://i-blog.csdnimg.cn/blog_migrate/de25d50f9f140d3fd646d564ee24c48a.png)
过程:一个项目是由多个.c文件.h头文件构建的:
- 多个.c文件分别进入编译器,编译处理生成相对应的目标文件
- 多个目标文件和链接库一起经过链接器处理生成最终的可执行程序
- 链接库是指运行时库(它是支持程序运行的基本函数集合)或者第三方库
我们画图了解一下
2.1 预处理(预编译)
在预处理此阶段, .c和.h文件会被处理为 .i 后缀的文件
此阶段的主要功能是:
- 1.删除所有我们写的注释(注释是给我们程序猿看的,不是给电脑看的哈哈)
- 2.将所有的#define删除,展开所有的宏定义
- 3.处理所有的条件编译指令,eg:#if #ifdef #elif #endif.....
- 4.处理#iclude预编译指令,将包含的头文件的内容插入到预编译指令的位置,此过程是递归进行的,头文件里包含的头文件会逐个被打开
- 5.添加行号和文件名标识,文便后续编译器生成调试信息等
- 6.或保留所有的#pragma的编译器指令,编译器后续会使用。
经过此阶段,生成的.i文件不会包含宏定义,头文件里内容都被插入到.i文件里
2.2 编译
此过程就是队.i文件进行词法分析,语法分析,语义分析及优化,生成相应以.s为后缀的汇编代码
2.2.1 词法分析:
将代码程序输入扫描器,对程序进行词法分析,把代码的字符分割成一系列的记号
将会得到一下16种记号:
2.2.2 语法分析:
此阶段会由语法分析器对扫描器产生的的记号进行语法分析,从而产生语法树
比如:我们进行加法的编写等等
2.2.3 语义分析:
经过语法分析得到的语法树,我们此阶段来完成语义分析,就是进行浅层面分析,主要完成声明,匹配,转换等,此阶段会报出编写的语法错误
2.3 汇编:
汇编器是将汇编代码转转变成机器可执行的指令,每⼀个汇编语句几乎都对应⼀条机器指令。就是根据汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化。
2.4 链接:
链接把一堆文件链接在一起
链接过程主要包括:地址和空间的分配,符号决议,重定位等等
链接解决的是⼀个项目中多文件、多模块之间互相调用的问题
![](https://i-blog.csdnimg.cn/blog_migrate/e0df730bd042f38478ab6e5112118db0.png)
根据我们之前的步骤,我们这里写的test.c和print.c源文件都单独经过编译器处理得到对应的目标文件 :
test.c --->test.o
print.c --->print.o
我们在test.c文件中使用了一次print,c中的print函数时必须确切知道print函数的地址,但是由于两个文件时
单独编译的,所以
我们无法知道他的地址.
所以暂时把调用print
的指令的目标地址
搁置。等待最后链接的时候由
链接器根据引用的符号print
在其他模块中查找print
函数的地址,然后将
test.c
中所有引用到
print
的指令重新修正,让他们的目标地址成为真正的print
函数的地址,这个地址修正的过程叫做:重定位.
![](https://i-blog.csdnimg.cn/blog_migrate/219dceb6c4541e5c0d1050ad07a2866b.png)
3.运行环境
1.
程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2.
程序的执⾏便开始。接着便调⽤main函数。
3.
开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程⼀直保留他们的值。
4.
终止程序。正常终止main函数;也有可能是意外终止。