2.1 被隐藏了的过程
4个步骤:预处理、编译、汇编、链接
2.1.1 预编译
gcc -E hello.c -o hello.i
或者 cpp hello.c > hello.i
预编译过程主要处理那些源代码文件中以#开始的预编译指令,比如#include、#define等主要处理规则如下
- 将所有的#define删除,并展开所有宏定义
- 处理所有条件编译指令,比如#if #ifdef #elif #else #endif
- 处理#include预编译指令,将被包含的文件插入到该预编译指令的位置,这个过程是递归进行的,就是说被包含的文件可能还包含其他文件
- 删除所有的注释
- 添加行号额文件标识,比如#2 hello.c 2, 以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示的行号
- 保留所有的#pragma编译器指令,因为编译器须要使用它们
经过编译处理后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到i文件中
2.1.2 编译
编译过程就是把预处理万的文件进行一系列词法分析、语法分析、语义分析及优化后生产响应的汇编代码文件。这个部分是核心部分,也是最复杂的部分之一
gcc -S hello.i -o hello.s
2.1.3 汇编
汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。as hello.s -o hello.o
2.1.4 链接
将在后面详细讲解,这里不做记录
2.2 编译器做了什么
编译器就是将高级语言翻译成机器语言的一个工具。
使用机器指令或者汇编语言十分费事,开发效率低下,并且依赖于特定的机器,一个为某种CPU编写的程序在另外一个cpu下完全无法进行,要重新编写,所以希望采用自然语言来描述程序。所以就有了FORTRAN和C
编译过程一般可以分为6步:扫描、语法分析、语义分析、源代码优化、代码生成、目标代码优化
2.3 链接器年龄比编译器长
程序设计的模块化
最常见的属于静态语言的C、C++模块之间通信有两种方式,一种是模块间的函数调用,另外一种是模块间的变量访问。
函数访问必须知道目标函数的地址,变量访问也需知道目标变量的地址,所以这两种方式可以归为模块间符号的引用。
2.4 模块拼装–静态链接
链接过程包括了地址和空间分配、符号决议、重定位等步骤
2.5 本章小结
4个步骤:预编译、编译、汇编、链接
编译步骤:词法分析、语法分析、语义分析、中间代码生成、目标代码生成与优化
静态链接的基本概念:重定位、符号、符号决议、目标文件、库、运行库