Linux C编译原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/localhostcom/article/details/82890197

一.基本概念

1.编译程序:把一种语言(源语言---高级语言)转换成另一种语言(目标语言---低级语言--> 汇编或机器语言)。

2.词法分析:对输入的字符串进行扫描和分解,识别出一个个字符及其数据类型;

3.语法分析:对输入的字符串进行语法单位的识别,判断是一个赋值语句还是其它表达式。

4.语义分析与中间代码的产生:对输入的出现字符串进行语法的检查,合法会进行初步的翻译。(输入的是语法单位,输出的时是翻译的初步代码)。

5.优化器:对初步翻译得到的代码进行再次扫描和翻译,去掉冗余。(输入的是初步的翻译结果,输出是优化后代码)。

6.目标代码生成器:对于优化后的代码进行再次翻译,生成符合机器的最终代码(输入的是优化后代码,输出是符合机器的目标代码)。

7.出错处理:编译过程中有错误出现的报错处理,具体的事故地点,原因,尽量缩小范围,使源程序的其余部分继续执行。

8.编:就是对源程序或源程序的中间结果进行从头到尾的依次扫描,并且做出相应的处理,生成新的中间结果或目标程序。词法分析相当于一遍,语法分析又一遍,但词法,语法可以合为一遍,根据自身的内存情况来定。

二.编译过程

C语言编译的完整过程:C源程序 ---> 预编译 ---> 编译、优化 ---> 汇编 ---> 链接程序 ---> 可执行文件

也可简化为4步:  预处理 ---> 编译 ---> 汇编 ---> 链接。

1.预处理

包括以下几个过程:

a.宏定义指令:将所有的#define删除,并且展开所有的宏定义。

b.条件编译指令:处理所有的条件预编译指令,比如:#if , #ifdef , #elif , #else , #endif等。 

c.头文件包含指令:处理#include预编译指令,将包含的文件插入该预编译指令的位置。

d.特殊符号指令:预编译其可识别一些特殊的符号,比如:删除所有的注释"//"和"/**/"。

e.添加行号和文件标识,以便编译时产生调试用的行号及编译错误警告行号。

f.保留所有的#pragma编译器指令,因为编译器需要使用它们。

使用以下命令来进行预处理:

gcc -E *.c -o *.i  //-E参数表示只进行预处理

2.编译

编译过程就是把预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。

使用以下指令进行编译:

gcc -S *.i  -o *.s

3.汇编

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎对应一条机器指令。根据汇编指令和机器指令的对照表一一翻译即可。

gcc -c *.c -o *.o

4.链接

通过调用连接器ld来链接程序运行需要的一大堆目标文件,以及所依赖的其它库文件,最后生成可执行文件。

链接的主要内容是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确地衔接,链接分为静态和动态链接。

a.静态链接:在编译阶段直接把静态库加入到可执行文件中去,会导致可执行文件比较大。静态库文件是一个二进制文件,在文件编译时要访问文件,编译后静态库文件可以删除,因为已经编译进可执行文件中了。(后缀名:.so)

b.动态库链接:是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应的动态库加载到内存中去,动态库文件是一个二进制文件,在文件执行时需要访问文件,编译时不需要访问动态库文件。(后缀名:.a)

三.程序执行过程

程序执行过程:

1. 程序必须载入内存中。在有操作系统的环境中:一般此过程由操作系统完成。独立环境中,程序载入必须手工完成,也可能通过可执行代码置入只读内存来完成。

2. 程序的执行便开始。接着调用main()函数。

3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈,存储函数的局部变量,函数参数,返回数据和返回的地址。同时也可以使用静态内存,存储于静态内存中的变量在程序的整个运行过程中一直保留它们的值。

4.终止程序。正常终止main函数,也可能会中途意外终止。

猜你喜欢

转载自blog.csdn.net/localhostcom/article/details/82890197
今日推荐