众所不周知,C语言的程序运行分为几个阶段。
咱们可以看看下面这个图,简单了解一二
细分开来,编译还分为3个小阶段:预编译(预处理)、编译、汇编
这三个阶段又分别做了什么事情呢?这就需要我们用linux下的gcc编译器来验证了
现在我们编写了一个这样的代码
在运行窗口中输入以下指令,进行预编译操作,得到test.i
文件
gcc -E test.c -o test.i
打开该文件,滑倒最底部,查看它与源代码的不同
可以发现以下几点:
这就是预编译阶段做的3件事,实际上都是一些文本操作,并没有运行该代码
输入以下指令,生成test.s
文件
gcc -S test.i -o test.s
打开该文件,发现我们好像看不太懂它里面写了些什么
实际上,mov
、sub
都是汇编语言,这一步就是把C语言代码转变成了汇编代码。 进行了以下几步操作:
这一部分内容可以阅读《程序员的自我修养》这本书,记录一下
gcc -c test.s -o test.o
这个指令会生成一个test.o
目标文件
.o
.obj
.o目标文件和可执行成句的文件格式
elf
readelf工具可以解析elf格式的文件
用文本编辑器打开这个文件,可以看到里面的东西都是乱码
实际上这个文件里面存放的是二进制内容。
汇编操作就是将汇编代码转换成二进制指令
其中有非常重要的一部:形成符号表
这个代码中其实包含了两个源文件:test.c
、Add.c
里面出现了两个符号,main和Add
编译器会先对每个源文件创立一个符号表,为它们添加一个类似地址的参数。在链接阶段的时候,相同符号的地址参数会被设置为一样的
这里编译会查看Add函数的定义在哪里
如main函数中只是extern,并没有Add的具体实现,最后链接之时,Add符号的地址会被设置为
Add.c
中该符号的地址
这个操作又叫:符号表的合并和重定位
链接阶段还会执行另外一个操作:合并段表
gcc test.o add.o -o test
//生成可执行程序test
使用./TEST
操作执行该文件,可以看到程序成功输出了Add后的答案
程序执行的过程中:
本篇博客中,我们认识了解了程序运行的几个阶段。这里面还有很多更深层次的问题待我去探究。
下篇博客:预处理详解
点个赞再走呗,谢谢!