预处理(Preprocessing)
- 任务:
处理源代码中以#
开头的预处理指令,包括:- 头文件包含(#include):将头文件(如 stdio.h)的内容直接插入到源文件中。
- 宏替换(#define):将代码中的宏定义(如 #define PI 3.14)进行文本替换。
- 条件编译(#ifdef #else #endif 等):根据条件决定代码的保留或删除(例如,区分调试和发布版本的代码)。
- 输出:生成一个经过预处理的中间文本文件(仍为可读文本,但已展开所有预处理指令)。
编译(Compilation)
- 任务:
将预处理后的代码转换为汇编语言代码。编译器会进行以下操作:- 词法分析:将代码分解成一个个单词(Token),例如识别关键字、变量名、操作符等。
- 语法分析:检查代码是否符合 C/C++ 语法规则(如括号是否匹配、语句是否完整)。
- 语义分析:检查代码的语义正确性(如变量是否先定义后使用、类型是否匹配)。
- 中间代码生成与优化:生成中间表示代码,并进行优化(如删除无用代码、优化循环),最终转换为汇编语言。
- 输出:生成汇编代码文件(如 Helloworld.s)。
汇编(Assembly)
- 任务:
汇编器(Assembler)将汇编语言代码转换为机器可识别的二进制目标文件(Object File,如 Helloworld.obj 或 Helloworld.o)。每个汇编指令会被映射为对应的机器码。 - 输出:生成二进制目标文件,此时文件中可能仍包含对其他函数(如标准库函数 printf)的未解析引用。
链接(Linking)
- 任务:
链接器(Linker)将多个目标文件(包括自身代码生成的 .obj 和依赖的库文件)链接成一个可执行文件(如 Helloworld.exe)。分为两种方式:- 静态链接:将库函数的代码直接复制到可执行文件中,最终文件较大,但运行时无需依赖外部库。
- 动态链接:仅记录对库函数的引用信息,运行时由操作系统加载对应的动态链接库(如 .dll 在 Windows 或 .so 在 Linux)。
链接过程会解析目标文件中的外部符号引用(如解决 printf 的具体实现来自哪里)。
- 输出:生成可直接运行的可执行文件。
运行(Execution)
- 任务:
操作系统加载可执行文件到内存中,创建进程,分配资源(如内存、文件句柄),然后执行程序的指令。程序从 main 函数开始执行,直到遇到 return 或 exit 等退出操作。