1. 程序的链接和编译
1.1 基本概念
在ANSI C的任何一个实现的方法之中,存在着两个不同的环境:
- 翻译环境,在这个环境之中源代码被转换成可执行的指令
- 执行环境,它是用来实际执行代码
所有的源文件都要经过上述两个程序之后才能称为可执行文件。
在一个工程之中可能有多个.c.h等,他们通过一系列的步骤形成一个可执行文件
1.2 翻译环境
在翻译环境之中,还可以分为两个阶段,分别为编译(编译器)与链接(链接器)两个部分,其中编译器可以分为预编译(预处理),编译,汇编三个部分。
1.3 编译阶段
1.3.1 预编译
预编译阶段主要功能为:
- 头文件的包含
- 注释的删除
- #define定义符号的替换
- #pragma pack等符号的处理
C++ |
1.3.2 编译
在gcc编译中指令:gcc:test.i -s生成一个.s文件
编译的主要的功能为:将c翻译成汇编代码
- 语法分析
- 词法分析
- 语义分析
- 符号汇总
其中符号汇总,属于编译原理之中的知识也是最难理解的,简单的来说就是将源文件之中定义的函数等符号进行汇总到一起。
eg:add.c
C++ |
test.c
C++ |
test.c调用了add.c的外部函数,所以在进行编译时分别进行符号汇总,在汇编阶段进行形成符号表,在链接时进行合并符号表,合并段表
如果在内存之中无法在实际的地址上找到函数,就会发生链接报错
1.3.3 汇编
gcc指令:test.s -c 生成test.o文件
汇编的功能:生成目标文件是二进制文件
- 将汇编代码转换二进制文件
- 形成符号表
1.4 链接阶段
链接阶段目标文件是一个二进制的文件,所以首先要进行合并段表,然后就是对符号表进行合并,查找符号表上对应地址是否正确。
1.5 程序执行阶段
程序的执行的过程:
- 程序必须载入到内存之中,在有操作系统的环境之中,一般是由操作系统来进行完成。在独立的环境之中,程序的载入必须由手工来安排,也可能是通过可执行代码置入只读内存来进行完成。
- 程序的执行便开始。接着调用main函数
- 开始执行程序的代码。这个时候程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态内存。存储于静态内存中的变量在程序的整个执行的过程一直都保存着他们的值。
- 终止程序。正常终止main函数,也可能是意外的终止。