源文件需要编译链接的原因:
由于计算机只能识别机器语言,不能直接识别我们所编写的 .c 或 .cpp 文件。因此,需要将这些文件通过编译链接过程生成最终的可执行文件,使得计算机能够识别进而运行。
编译链接的四个阶段:预编译、编译、汇编、链接。
一、预编译阶段
将源代码文件.c 或 .cpp 和相关的头文件.h 等预编译成一个 .i 文件
gcc -E hello.c -o hello.i (-E表示只预编译)
预编译阶段完成的工作:
①:删除#define并进行文本替换
②:处理预编译指令,例如 “if”,“ifdef”,“ifndef”,“endif”,“else”
③:递归展开 #include
④:删除注释,例如 “//”,“/**/”
⑤:添加行号和文件标识,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够产生行号。
⑥:保留#pragma指令,给编译器处理
二、编译阶段
将预编译后的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码 .s 文件
gcc -S hello.i -o hello.s (-S表示只编译)
或者:
gcc -S hello.c -o hello.s
编译阶段完成的工作:
①:词法分析
根据类似于有限状态机的算法可以轻松地将源代码的字符序列分割成一系列的记号。词法分析产生的记号一般分为如下几类:关键字,标识符,字面量(包含数字,字符串等),和特殊符号(如加号,等号)。
②:语法分析
语法分析器将由词法分析产生的记号进行语法分析,从而产生语法树(Syntax Tree)。语法分析仅仅完成了对表达式的语法层面的分析,它并不了解这个语句是否真正有意义。
③:语义分析
对表达式所包含的真正意义进行确定,隐式类型转换会在这里进行,若转换不了,则进行报错。由语义分析器来完成,经过语义分析阶段后,整个语法树的表达式都被标记了类型,如果有些类型需要做隐式类型转换,语义分析程序会在语法树中插入相应的转换节点。
④:代码优化
⑤:生成汇编指令
三、汇编阶段
将汇编指令翻译成二进制格式,生成相应的汇编代码 .o 文件。
gcc -c hello.s -o hello.o
或者编译整个过程:使用gcc命令从 .c 文件一步生成 .o 文件
gcc -c hello.c -o hello.o
四、链接阶段
gcc -o hello hello.o --> 生成最终的可执行文件 .exe
或者:
gcc -o hello hello.c
链接阶段完成的工作:
①:合并段和符号表
②:符号解析
③:分配地址和空间
④:符号重定位