编译器是由几部分组成的,包括预处理器,编译器,汇编器,链接器。
我们写的代码经过预处理器,变成 .i 文件,再经过编译器处理,变成 .s 文件,再经汇编器,生成 .o 文件,最后经链接器,变成可执行文件。
预处理器,编译器,汇编器,链接器都做了什么呢,我们接着看
处理所有的注释,以空格代替
将所有的 #define 删除,并且展开所有的宏定义
处理条件编译指令 #if,#ifdef,#elif,#else,#endif
处理 #include,展开被包含的文件
保留编译器需要使用的 #pragma
预处理指令实例:gcc -e file.c -o file.i
gcc -e 19-1.c -o 19-1.i
得文件 19-1.i 文件,下面是 19-1.i 文件
可以看到,注释被直接去除,头文件被直接展开,宏定义被直接展开。以 # 开头的信息是给后续编译器其他模块使用的。
对预处理文件进行词法分析,语法分析和语义分析
词法分析:分析关键字,标示符,立即数等是否合法
语法分析:分析表达式是否遵循语法规则
语义分析:在语法分析的基础上进一步分析表达式是否合法
分析结束后进行代码优化生成相应的汇编代码文件
编译指令实例:gcc -s file.i -o file.s
gcc -s 19-1.i -o 19-1.s
生成 19-1.s 如下,里面的汇编代码这里不做解析了。
汇编器将汇编代码转变为机器的可以执行执行
每条汇编语句几乎都有对应一条机器指令
汇编指令示例:gcc -c file.s -o file.o
gcc -c 19-1.s -o 19-1.o
生成文件19-1.o,这里还不是可执行文件。
经过链接器处理才能生成可执行文件:gcc 19-1.o -o 19-1
编译过程分为预处理,编译,汇编和链接四个阶段
1、预处理:处理注释,宏以及以 # 开头的符号
2、编译:进行词法分析,语法分析和语义分析等
3、汇编:将汇编代码翻译成机器指令的目标文件