程序编译的四个阶段
#include <stdio.h>
int main(){
printf("Hello World~");
return 0;
}
hello.c程序的生命周期从一个高级C语言程序开始,这种形式容易被人读懂。 但这无法直接被计算机读懂。为了在系统上运行hello.c程序,每条C语言都必须被其他程序转化为一系列的低级机器语言指令。
机器语言是一种以01的表现形式的二进制代码,因此源程序的编译过程就是:将以高级语言编写的程序转换为二进制代码的形式的可执行目标程序。
浅理解
由于现在正处于初步理解阶段,所以这里先进行“浅理解”:
浅理解:不要求深入探讨原理等复杂内容,仅从表面用法和便于记忆的角度进行讲解。重点是快速上手和形成初步印象的内容。主求会用,略求原理。
预处理阶段:
在这个阶段,预处理器会根据预处理指令(如#include、#define 等)对源代码进行处理。对于#include <stdio.h>,预处理器会将头文件 stdio.h 的内容插入到当前代码位置,展开宏定义,并处理条件编译指令等。其目的是为后续的编译阶段准备完整且经过初步处理的源代码文本。
编译阶段:
编译器将预处理后的源代码转换为低级的中间表示形式,通常是一种类似于汇编语言但更为抽象的形式。在这个过程中,编译器会进行语法分析、语义分析和代码优化等操作。语法分析检查代码是否符合 C 语言的语法规则;语义分析确保代码在语义上是正确的,例如变量的使用是否合法等;代码优化则旨在提高生成代码的效率。如果在这个阶段发现语法错误或语义错误,编译器会报告错误信息。
汇编阶段:
汇编器将编译阶段生成的中间表示形式转换为特定机器架构的汇编语言代码。汇编语言是一种低级语言,更接近机器语言,但仍然相对易于人类阅读和理解。在这个阶段,汇编器会将各种指令和操作转换为对应的机器指令的助记符形式。
链接阶段:
链接器将多个目标文件(可能包括由当前代码生成的目标文件以及其他库文件中的目标文件)链接在一起,生成可执行程序。如果代码中调用了外部库函数(如 printf),链接器会将这些函数的实现与当前代码进行链接,确保程序在运行时能够正确地调用这些函数。链接阶段还会处理符号解析、地址分配等任务,以确保程序能够正确地加载和运行。
通俗理解
预处理阶段:
这个阶段就像是给代码做准备工作。比如说,代码里有#include <stdio.h>,在这个阶段,就会把`stdio.h`这个文件里的内容拿过来放到咱这个代码里。就好像你要做一顿饭,先把要用的调料啥的都准备好放在旁边。预处理阶段还会处理一些其他的指令,比如宏定义啥的。总之,就是把代码整理得更完整,为后面的阶段做准备。
编译阶段:
时候呢,就开始把咱的 C 语言代码翻译成机器能懂的语言啦。不过这时候还不是最终的机器语言,更像是一种中间形式。就好比你跟一个外国人说话,你把你的话翻译成一种他能大概明白的中间语言。这个阶段会检查语法错误啥的,如果有错误就会告诉你,让你去改。
汇编阶段:
在这个阶段,把上一个阶段得到的中间语言进一步翻译成机器语言,但是是一种比较低级的机器语言,叫做汇编语言。这就像是把那个中间语言再进一步细化,变成更具体的指令。可以想象成把一个复杂的任务分解成一个个小步骤,每个小步骤都用特定的指令表示。
链接阶段:
最后这个阶段呢,就是把咱的程序和其他需要的东西连接在一起。比如说,如果你的程序用到了一些别人写好的库函数,像`printf`函数就是在`stdio.h`这个库里的。在链接阶段,就会把你的程序和这些库连接起来,让你的程序能正常运行。就好像你做好了一道菜,最后要装盘,把菜和盘子组合在一起,这样才能端上桌。