程序有翻译环境和执行环境
在ANSI C的任何一种实现中,存在两个不同的环境。
第1种是翻译环境,在这个环境中源代码被转换为可执行的 机器指令(二进制指令)。
第2种是执行环境,它用于实际执行代码。
在翻译环境下有 编译 和 链接 两大过程,接下来举例说明。
例子:
在VS2019环境下,创建 test.c 和 add.c 两个文件。
编译 和 链接 的过程:将 test.c 和 add.c 两个源文件,经过cl.exe编译器进行编译,生成test.obj 和 add.obj 两个目标文件,再将这两个目标文件经过link.exe链接器进行链接,生成可执行程序test.exe。
Linux gcc来演示编译链接的过程
VS2019 集成开发环境不方便观察每个细节
我们使用 Linux gcc来演示编译链接的过程
windows 环境下的目标文件 xxx.obj
Linux 环境下的目标文件 xxx.o
目标文件里面是二进制指令!!!
Linux环境下:test.o可执行程序的格式是:elf <---可以用readelf工具读取
Linux环境下:头文件放在/usr/include
编译分为三个阶段:一、预编译阶段 二、编译阶段 三、汇编阶段
在预编译(预处理)阶段的工作:
1.头文件的包含,2.define定义符号的替换,3.注释删除
在Linux - gcc环境下,对源文件的代码进行处理,输入命令gcc test.c -E -o 可得到test.i文件,输入命令gcc add.c -E -o 可得到add.i文件。test.i和add.i这两个文件会为下一个阶段生成汇编代码做准备。
在编译阶段的工作:
把C语言代码翻译成汇编代码,其中翻译工作包括1.语法分析2.词法分析3.语义分析4.符号汇总,符号汇总是为下个阶段生成符号表做准备。
在Linux - gcc环境下,对test.i和add.i两个文件的代码进行处理,输入命令gcc test.i -S 可得到test.s文件,输入命令gcc add.i -S 可得到add.s文件。test.s和add.s这两个文件会为下一个阶段生成目标文件做准备。
在汇编阶段的工作:
把汇编指令翻译成二进制指令,并生成符号表。
在Linux - gcc环境下,对test.s和add.s两个文件的代码进行处理,输入命令gcc test.s -c可得到test.o文件,输入命令gcc add.s -c 可得到add.o文件。test.o和add.o这两个文件会为链接阶段生成可执行程序做准备。
链接阶段
在链接阶段的工作:
1.合并段表,2.符号表的合并和重定位
在Linux - gcc环境下,通过链接器将test.o和add.o这两个目标文件(或许还会有库文件)链接在一起生成一个完整的可执行程序。 链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。在此过程中会发现被调用的函数未被定义。需要注意的是,链接阶段只会链接调用了的函数 / 全局变量,如果存在一个不存在实体的声明(函数声明、全局变量的外部声明),但没有被调用,依然是可以正常编译执行的。
经过以上 编译 和 链接 两大阶段,便可生成可执行程序 test.exe。