流程概况:将源代码转换成机器可识别代码的过程,编译程序读取源代码,对他进行词法和语法的分析,将高级语言转化为功能等效的汇编代码,然后转化为机器语言,按照操作系统对可执行文件格式的要求连接生成可执行程序
源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件
编译预处理
读取源代码,对其中的伪指令(#开头)和特殊符号进行处理.
- 宏定义
#define Name TokenString
:将所有Name
替换成TokenString
#undef
: 取消宏定义 - 条件编译
#ifdef
,#ifudef
,#else
,#elif
,endif
等等
这些伪指令让程序员通过不同的宏决定编译程序对那些代码进行处理,从而把不必要的代码过滤掉 - 头文件包含指令
#include "FileName"
,#include <FileName>
- 头文件中有大量的宏定义,还有外部符号的声明
采用头文件的目的是让某些定义供不同的 C 源程序使用,因为只要加上一条#include
,就可以把这些定义和声明加入到对应的源程序文件中. - 系统提供的头文件一般放在
/usr/include
下,需要使用<>
来包含他们,而开发人员自己的头文件一般在同一目录下,此时要用""
- 头文件中有大量的宏定义,还有外部符号的声明
- 特殊符号
预编译可以处理一些特殊符号,比如LINE
是当前的行号(十进制),FILE
是当前源程序的名称.预编译会识别这些特殊符号.
总结:这个阶段主要是对源程序的"替换"工作,替换后,上面的四个东西就消失了,得到一个没有上述特性的输出文件.
编译阶段
在预处理之后,编译通过词法和语法分析,将输出文件翻译陈等价的中间代码或者汇编代码.
优化阶段
比较复杂, 比如删除公共表达式, 循环优化, 无用赋值的删除等等.
优化阶段放在编译之后,是一种比较笼统的表达
汇编过程
把汇编翻译成目标机器指令,每一个 C 语言源程序都会得到目标文件
目标文件由段组成:
- 代码段:程序本身
- 数据段
链接程序
上面的目标文件不能立即被执行,还有一些问题, 比如,某个源程序中的函数引用了另一个源文件中的符号, 调用了其他库中的函数,这些问题需要链接来实现.
链接的主要工作就是将有关的目标文件彼此链接,使得所有目标文件成为一个统一整体.
- 静态链接: 函数代码从所在的静态链接库中被拷贝到最终可执行程序中,在执行的时候这些代码被装入这个进程的虚拟地址空间中
静态链接库:目标文件的集合,每个文件含有库中一个或者一组相关函数的代码
- 动态链接: 这种方式下,函数的代码被放在动态链接库或者共享对象的某个目标文件中,链接只是在最终的可执行程序中,记录下共享对象的名字和一些登记信息,执行的时候,动态链接库中的全部内容被映射到相应进程的虚地址空间,动态链接程序通过可执行程序中的信息找到相应的代码.
动态链接能让程序更加短小,多个进程共享对象的时候能节省内存,但是某些情况下可能会有性能的损伤
网友评论