第一步:首先写好你要写的代码
#include <stdio.h> //引用头文件
#define M 1000 //定义字符M 的值为1000
#define MUL(x) (x)*(x) //定义宏
int main()
{
//打印内容
printf("预处理过程\n");
printf("i am a Mul:%d\n",MUL(3));
printf("i am a M:%d\n",M);
return 0;
}
第二步:预编译/预处理
在linux中可以用命令:gcc -E 文件名 来演示预编译(gcc -E 表示在预处理后停下来)
#这里的-o test2.i 表示把预处理后的临时内容放到文件test2.i中
然后我们查看一下test2.i里面预编译后究竟产生了什么内容
#vim test2.i - 用vim编辑器打开
与源文件对比发现:
1、int main()之前多了800多行代码,这800多行代码是头文件<stdio.h>的内容
2、#define 定义的内容被替换掉
3、注释不见了
总结:在预处理过程中会把头文件内容展开,#define定义的字符,宏会进行替换,注释会被删除
第三步:编译
在linux中用命令 gcc -S 文件名 ,把刚才预处理后的内容进行编译然后停下来!
#这里的-o test2.s 表示把编译后的临时内容放进test2.s 中
然后我们来看看编译后产生了什么内容
这些内容我们看不懂,这些究竟是什么东西呢?其实是汇编代码
所以编译这个步骤就是把我们写的代码转换为汇编代码,转换为汇编代码的过程中总共做了4件事:1. 语法分析 2. 语义分析 3. 词法分析 4.符号汇总 ; 然后就生成了我们现在看到的内容
第四步:汇编
在linux中我们用命令gcc 文件名 -c,把刚才编译后的内容进行汇编然后停下!
gcc -c 后产生的文件test2.o就是汇编后的内容,我们看看里面到底是什么?
我们看到又是一大堆看不懂的符号,其实这些全部是二进制指令,它现在是以文本的形式显示出来所以是看不懂的符号,我们用 od命令 查看
说明:od命令系统默认的显示方式是八进制
生成的.o文件(目标文件,windows里是.obj)其实是elf格式的文件
用readelf工具可以查看到elf文件里的内容
这是个什么东西呢?其实是一个符号表,我们在第三步编译的时候做的四件事里,最后一个是符号汇总就是把所有符号汇总起来到这里用上场了,生成符号表。
这个符号表的作用就是接下来的最后一步!
第五步:链接
把所有目标文件(.o文件)和链接库进行链接生成可执行文件(.exe文件)
它是如何进行链接的?
通过符号表的合并和重定位(每一个.o文件其实就是一个符号表),把所有符号表合并和重定位,把有用的符号留下,把重复多余的符号去掉,然后通过合并后的符号表就可以跨文件把所有.o文件链接在一起