加入光荣的进化吧!
目录
从文本文件到可执行文件
如果将操作系统看做一个世界,将用户看做造物主,文本文件就是我们作为造物主的简单造物,它普普通通,在操作系统中几乎没有什么高等级的权限,没有能力利用那无处不在的操作系统的资源——我们也可以称之为‘世界本源’。
而可执行文件便是那一种能力超凡的‘大修行者’,可以调动这个世界的力量,可以驱使其它的文件,甚至包括其它可执行文件为其使用——很可惜,这种非凡的力量是固化的,是只能由‘天’赐予的。
当一个文本文件触摸到了与本源接近的力量(各类语言编写程序),它便有蜕变出可执行文件的可能。而那个由文本文件到可执行文件的过程,被称为,进化!当然,我更愿称为,飞升!
PS.难得的中二一波,可补充设定的地方挺多的,但咱毕竟不是写小说的,就不完善了。
预处理
在编译最开始的时候,编译器会对涉及到的源代码文件及其相关的头文件进行预编译处理,其大致操作如下:
1.将所有的 “#define” 删除,并且展开所有的宏定义。
2.处理文件中的条件预编译指令,如 “#if” , “#ifdef” , “#elif” , “#else” ,“#endif” 等。
3.展开#include包含的头文件。
4.删除所有注释。
5.生成编译阶段需要用到的一些符号,如行号等。
6.保留所有的#pragma编译器指令。
编译
编译阶段主要是按照所使用的语言的语法规则来检测程序中是否由语法问题,如果有,则按照相应规则返回警告或者报错。这个过程是我们程序构建的核心过程,也是最复杂的部分之一——这也是为什么我们会习惯将这所有的阶段统称为编译。
大概经历了:
1.词法分析
2.语法分析
3.语义分析
4.中间语言生成
在此不做详细了解。
需要注意的是,编译阶段只编译源文件,不编译头文件——源文件中包含的头文件已经在源文件中展开了(预处理中做的)。每个源文件在编译后都会生成一个对应的目标文件。
汇编
这个阶段就像是一个翻译的过程,在编译阶段中,我们最初所使用的语言已经被拆解的面目全非,成为了让人看起来头疼无比的汇编指令。这已经达到了我们大部分人所能认识的语言的最底层了,但是,对于计算机来说,这依旧是天书一般。
所以我们需要汇编这个阶段,将一条条汇编指令通过汇编器转换成二进制文件。
链接
这就是飞升/进化的最后一个阶段了,经历了重重劫难,“雷劫淬体”之后,终于迎来了升华。
从理论上来说,经历了前三个阶段的洗礼之后,我们所拿到的二进制文件已经是一个“成熟”的可执行文件了,但实际上却不是如此。因为我们的程序不可能只由这一个文件组成,其背后一定包括了或是用户定义的其它的头文件与源文件(这个可以有),或是C/C++库的库文件(这个必须有)。只有将这所有的力量合而为一,才可以构建出真正完整的可执行文件。
所以,简单来说,链接就是将多个目标文件拼接成一个可执行文件。
而链接过程主要包括地址和空间分配、符号决议(符号绑定/地址绑定)、重定位等。
具体内容过于复杂,这里只是简单通俗地解释一下,只是大概理解。
我们上边说过,在预处理阶段,我们已经将头文件在源文件中展开了,而编译器在编译阶段的要求实际上并不严格,只要可以在文件中找到所使用函数的声明,就可以通过编译。
不过,编译器会对应地给所有声明了却没有实现地函数建立一个表。
而我们在文件中定义的全局变量或者实现地函数,对应的,编译器都会给与其一个入口地址,而这些函数及其地址,编译器也会为它们建立一个表。
而链接阶段编译器所主要做的操作,便是在所有文件提供的声明未实现函数表中寻找已实现函数及其入口地址地表中对应地函数。
如果所有的未实现函数都在入口地址表中找到了对应的入口地址,此所谓修行圆满,得道飞升。而一旦有一个函数没有寻到入口地址,其结果便是前功尽弃,复归尘土。