目录
前言
一、 程序的翻译环境和执行环境
二、翻译环境
2.1编译本身也分为三个阶段:
2.2预编译
2.3编译
2.4汇编
2.5链接
三、运行环境
总结
1.当我们刚开始学习c语言的时候。很多人都会被告知:一个程序是要经过编译--链接--执行这三个部分为,包括我记得大一时期末c语言的填空题也是如此。但是有没有人想过这看似简单的步骤其背后蕴含的复杂机制。比如:程序为什么要经过编译器进行编译后才可以运行?#include
2.本文章的程序都是centos7.6环境下运行的。
比如说我们创建一个test.c,我们就写一个非常简单的c语言程序。
我们编写的test.c就是一个源文件,它通过编译器编译成目标文件,再通过连接器链接成可执行文件。编译是针对一个源文件的,有多少个源文件就需要编译多少次,就会生成多少个目标文件。
还是拿上面写的test.c为例,在编译的过程中会先进行--预编译--编译--汇编,这三个阶段,每个阶段编译器都有不同的职责。
在Linux的环境下如果我们想要查看,test.c预编译后会产生哪些变化,我们可以输入指令gcc -E test.c -o test.i,此时我们查看test.i这个文件
这时我们发现在test.i这个文件中
1.#include
2.我们写的注释消失不见了
3.我们定义的#define MAX 20 被替换了
由此我们可以得出结论在预处理阶段编译器为我们做了:
1.展开头文件
2.#define 定义符号的替换
3.删除注释
在编译阶段,编译器会进行,1.语法分析(检测是否有语法错误)2.词法分析 3.语义分析 4.符号汇总,最终转化为汇编代码。而这一块都知识涉及到编译原理相关的知识,这里不做展开详解,如有兴趣的同学,可以看看编译原理相关的书。
在汇编阶段,编译器会将已经经编译好的test.c里面的汇编代码转化为二进制指令(机器指令)
在Linux我们可以通过输入指令gcc -c test.c 得到test.o文件进行查看
此时我们可以看到很多我们看不懂的乱码,这些就是二进制指令。
链接的主要功能是:1.合并段表 2.符号表的合并和符号表的重定位。如果你对这个功能的阐述不理解的话可以看下面的解释:
C语言代码经过编译以后,并没有生成最终的可执行文件(.exe 文件),而是生成了一种叫做目标文件(Object File)的中间文件(或者说临时文件)。目标文件也是二进制形式的,它和可执行文件的格式是一样的。对于 Visual C++,目标文件的后缀是.obj
;对于 GCC,目标文件的后缀是.o
。
链接就是一个“打包”的过程,它将所有的目标文件以及系统组件组合成一个可执行文件。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
如果大家还想进一步了解程序的编译,大家可以看《程序员的自我修养》这本书,这里面主要是讲解编译链接执行是如何实现的。