编译的那些事

一、简单介绍

首先我们先了解下什么是编译,编译其实简单来说就是把我们写的高级代码,翻译成另一种语言(称为目标代码)。而编译是由编译程序来做的,很多计算机都配有不止一种高级语言的编译程序,编译程序又可以理解为语言翻译程序。

编译程序的好处

有了编译程序的存在可以使得程序员不必去考虑与机器有关的琐碎的细节,这对于当今机器的数量和种类持续不断地增长的年代是很重要的,如果没有编译程序,我们就需要自己去考虑把我们的高级语言代码转换为底层执行代码显然是一个很麻烦的事情。

下面我们再去看下一个程序设计语言程序的典型的处理过程
处理过程

这里再解释下预处理程序、编译程序、汇编程序、装配/连接编辑程序的作用

  • 预处理程序:对于有一些预处理程序,如果一些源程序有的时候分成几个模块存放在不同的文件中,将这些源程序汇集在一起就属于预处理程序做的事情,还有就是宏的展开等任务也是它做的
  • 编译程序:将预处理后的源程序转换为汇编程序或者是二进制文件
  • 汇编程序:将汇编语言翻译成机器语言指令
  • 装配/连接编译程序:去连接某些库程序才能够去产生真正能够在机器上运行的代码,比如说C语言的连接程序是这样运作的,如果说我们写了一个源程序中使用了printf函数的话,由于它是一个c标准库里的函数。所以会将printf函数存放在一个名为printf.o的单独预编译的文件中。而这个文件必须以适当的方式并入到我们的程序中,这个工作由链接器完成。将外部的.o文件并入后,得到一个完整的可执行文件。可执行文件加载到存储器后,由系统进行复制执行

二、编译过程

编译程序完成了从源程序到目标程序的翻译工作,这个过程其实是很复杂的,这个工作过程是划分阶段来进行的,在每个阶段会将源程序的一种表示形式转换成另外一种形式,在各个阶段进行的操作在逻辑上是紧密的连接在一起的。一般来说编译程序可以划分为词法分析语法分析语义分析中间代码生成代码优化目标代码这6个阶段。

即过程如下所示
过程

1、词法分析

词法分析是编译程序的第一个阶段,这个阶段的任务主要就是从左到右的去一个一个字符的去读取源程序,对构成源程序的字符流进行扫描和分解,从而去识别出一个个的单词,就比如说 int a = 10; 就会去识别出int 、a、=、; 这四个单词,然后组成单词序列

2、语法分析

语法分析是编译程序的第二个阶段,这个阶段的任务就是在词法分析的基础上将单词序列分解成各类语法短语,这种语法短语也称为语法单位,可以表示成语法树,比如说int a = 10 可以表示为
语法树
其实关于语法分析所依据的是语言的语法规则,通过语法分析可以确定一个输入串是否可以构成语法上正确的程序。

3、语义分析

扫描二维码关注公众号,回复: 963898 查看本文章

语义分析做的事情是去审查源程序有无语义错误,为代码生成阶段去收集类型信息,也就是说语义分析的一个工作其实就是进行类型审查,审查每个运算符是否具有语言规范允许的运算对象,当不符合语言规范的时候,编译程序就会报告错误。比如说有的编译程序如果要对实数去做数组的下标就会报错。

4、中间代码的生成

在上面的工作完成之后,有的编译程序会将源程序变成一种内部的表示形式,这种内部的表示形式叫做中间语言或者叫做中间代码。其实中间代码就是一种结构简单、含义明确的记号系统,这种记号系统可以设计为多种多样的形式,重要的设计原则有两点:一个就是容易生成中间代码,还有一个就是容易将其翻译成目标代码。很多编译程序其实是采用了一种近似三地址指令的四元式的中间代码,之所以所四元式是因为里面有四个字段,当然这四个字段不一定都用到,三地址指令是因为里面有两个运算对象和一个结果对象,这种四元式的形式为
(运算符,运算对象1,运算对象2,结果)
比如说int a = 10 表示为四元式就是( = - 10 a )

5、代码优化

这一阶段的任务就是对前一阶段产生的中间代码进行变换或者是进行改造,目的就是为了使生成的目标代码更加的高效,这一既可以省空间又可以省时间。就比如说做的优化可以把我们源程序中原本生成中间代码需要18条来表示的,可以缩成10条来表示,这一也算一个优化。

6、目标代码的生成

这个阶段的任务就是把中间代码变换成特定机器上的汇编指令代码或者是二进制文件代码
它的工作和硬件系统结构和指令含义有关因为涉及到汇编,这个阶段会涉及到硬件系统功能部件的运用,机器指令的选择、各种数据类型变量的存储空间分配以及寄存器和调度等等。

当前上面所提的编译过程只是说一种典型的处理模式,不同的编译器肯定是不一样的,有一些编译器根本就不需要去生成中间的代码,有些编译程序则不进行优化,又有些编译程序在语法分析的同时就会去产生目标指令代码了。

其实一个完整的编译过程除了上面的提到的操作其实还需要表格管理程序和出错处理程序,因为在编译过程中源程序的各种信息需要被保留到不同的表格当中,编译的各个阶段都涉及到构造、查找和更新有关的表格,因此需要有一个表格管理程序,这里的表格可以理解为就是存放一些信息的地方。

以及如果编译过程中发现源程序当中有错误,编译程序应该去报告错误的信息和错误发生的地点,并且将错误造成的影响缩小到最小,使得源程序的其余部分能继续被编译下去,有些编译程序还可以自动的校正错误,这些其实都是由出错处理程序完成的。

关于一个可执行文件其实是包括了两部分内容的,一个就是程序还有一个就是关于程序相关的描述信息,其中程序中包含的就是最终由计算机执行、处理的指令或者数据。程序的描述信息指的就是程序有多大,要占据多少内存空间。

在编译一个源文件时,编译器的处理过程会分为几个阶段。如果我们想要去查看编译 main.m 源文件需要几个不同的阶段,我们可以让通过clang -ccc-print-phases main.m命令观察

这里写图片描述

猜你喜欢

转载自blog.csdn.net/ZCMUCZX/article/details/79952952