一.编译原理
一般高级语言程序编译的过程:预处理、编译、汇编、链接。
1.预编译
预编译又称为预处理,是做些代码文本的替换工作。是整个编译过程的最先做的工作。
预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。常见的预编译指令有:
(1)#include 指令
该指令指示编译器将xxx.xxx文件的全部内容插入此处。若用<>括起文件则在系统的INCLUDE目录中寻找文件,若用" "括起文件则在当前目录中寻找文件。一般来说,该文件是后缀名为"h"或"cpp"的头文件。
注意:<>不会在当前目录下搜索头文件,如果我们不用<>而用""把头文件名扩起,其意义为在先在当前目录下搜索头文件,再在系统默认目录下搜索。
(2)#define指令
该指令有三种用法:
第一种是定义标识,标识有效范围为整个程序,形如#define XXX,常与#if配合使用;
第二种是定义常数,如#define max 100,则max代表100(这种情况下使用const定义常数更好,因为:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生错误;
第三种是定义"函数",如#define get_max(a, b) ((a)>(b)?(a):(b)) 则以后使用get_max(x,y)就可以得到x和y中较大的数;
第四种是定义"宏函数",如#define GEN_FUN(type) type max_##type(type a,type b){return a>b?a:b;} ,使用时,用GEN_FUN(int),则此处预编译后就变成了 max_int(int a,int b){return a>b?a:b;},以后就可以使用max_int(x,y)就可以得到x和y中较大的数。
2.编译
2、用编译程序产生目标程序的动作。 编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。
3、 编译程序把一个源程序翻译成目标程序的工作过程分为五个阶段:词法分析;语法分析;语义检查和中间代码生成;代码优化;目标代码生成。主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,给出提示信息。
(1)词法分析的任务是对由字符组成的单词进行处理,从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号, 把作为字符串的源程序改造成为单词符号串的中间程序。执行词法分析的程序称为词法分析程序或扫描器。
(2)语法分析是以单词符号为输入分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后 看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序 是最终的一个语法单位。
(3) 中间代码是源程序的一种内部表示,或称中间语言。中间代码的作用是可使编译程序的结构在逻辑上更为 简单明确,特别是可使目标代码的优化比较容易实现中间代码,即为中间代码程序,中间语言的复杂性介于原程 序语言和机器语言之间。
(4)代码优化是指对程序进行多种等价变换,使得从变换后的程序出发,能生成更有效的目标代码。所谓等价,是指不 改变程序的运行结果。所谓有效,主要指目标代码运行时间较短,以及占用的存储空间较小。这种变换称为优化。
(5)目标代码是编译的最后一个阶段。目标代码生成器把语法分析后或优化后的中间代码变化为目标代码。
3.汇编
汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令在汇编语言中,用助记符(Memoni)代替操作码,用地址符号(Symbol)或标号(Label)代替地址码。这样用符号代替机器语言的二进制码,就把机器语言变成了汇编语言。于是汇编语言亦称为符号语言。
4.链接
链接是处理可重定位文件,把它们的各种符号引用和符号定义转换为可执行文件中的合适信息(一般是虚拟内存地址)的过程。链接又分为静态链接和动态链接,前者是程序开发阶段程序员用ld(gcc实际上在后台调用了ld)静态链接器手动链接的过程,而动态链接则是程序运行期间系统调用动态链接器(ld-linux.so)自动链接的过程。
(1)静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或 目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。静态链接的最大缺点是生成的可执行文件太 大,需 要更多的系统资源,在装入内存时也会消耗更多的时间。
(2)动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如 库)作为加载过程的一部分。在这些系统上,可执行文件包含一个叫做import directory的表,该表的每一项包含一 个库的名 字。根据表中记录的名字,装载程序在硬盘上搜索需要的库,然后将其加载到内存中预先不确 定的位置,之后根据加载库后确定的库的地址更新可执行程序。