001.在hello world中编译器工具链分别做了什么
为便于理解底层原理,本文中所有操作均在cmd中使用gcc实现
一、预处理器(gcc -E -o a.i a.c)
预处理的分类(以#开头)
-
包含头文件
#include -
宏定义(替换)
'define 宏名 宏体''define ABC 10'(将ABC替换为10)
想要得到一个仅被预处理的文件,我们可以在文件所在目录下打开命令行,输入'gcc -E -o a.i a.c'。
这里的-E是指仅进行预处理操作,-o指将a.c的操作结果写入a.i,可知预编译文件后缀为i -
条件编译
#ifdef DEBUGprintf("hello world!\n"); #endif
根据是否定义DEBUG,我们可以决定是否编译printf,尽管我们可以在预处理的部分直接定义DEBUG,但这样会更改他人的代码,
这是不合适的。
我们可以在cmd中手动打开:gcc -DDEBUG -o build a.c (build为exe文件)
二、编译器(gcc -S -o a.s a.i) 汇编器(gcc -c -o a.o a.s)
gcc是十分智能的,我们这里对整个编译过程进行分解,但如果我们输入gcc -c -o a.o a.c,gcc会自动帮我们完成预处理和编译工作。
这里我们主要理解产生可执行文件的过程:
人 --- 编译 --- 汇编语言
汇编语言 --- 汇编 --- 机器指令集
机器指令集 --- 链接 确定数据的地址 --- 可执行文件
下面我们来看链接器
三、链接器 (gcc -o build.exe a.o)
链接器主要用于确定数据的地址,链接过程常见的错误就是一些需要使用的数据我们并没有定义,或者一些调用的函数我们没有去定义,链接器就会报错。