这一章节主要是通过介绍HelloWorld程序的生命周期,对计算机系统的主要概念做了一个概述
The Lifetime of Hello Program(Hello程序的生命周期)
#include<stdio.h>
int main(){
printf("Hello World\n");
return 0;
}
源代码编写完成之后,保存得到一个后缀名 .c 的文件 —— hello.c
The Compilation System(编译系统)
linux> gcc -o hello hello.c
- 第一阶段 —— 预处理阶段
预处理器会根据以#开头的代码,来修改原始程序
例如 hello 程序中引入了头文件 —— stdio.h
预处理器会读取该头文件中的内容,将其中的内容直接插入到源程序中,结果就得到了另外一个 C 程序,这个经过预处理器处理后得到的文件通常以 .i 结尾
说白了就是,hello.c 经过预处理器后得到 hello.i,这个hello.i 仍旧是一个文本文件
- 第二阶段 —— 编译阶段
编译器将 hello.i 文件翻译成 hello.s 文件,这一过程我们称为编译,其中编译这一阶段包括词法分析、语法分析、语义分析,中间代码生成以及优化等等一系列的中间操作
(更进一步了解,可以阅读《编译原理》,也许几年内我会做编译原理的笔记)
- 第三阶段 —— 汇编阶段
汇编 器根据 指令集 将汇编程序 hello.s 翻译成机器指令,并且把这一系列的机器指令按照固定的规则进行打包,得到可重定位目标文件——hello.o
此时 hello.o 虽然是一个二级制的文件,但是还是不能执行,还要经历最后一个阶段——链接
- 第四阶段 —— 链接阶段
在hello这个程序中,我们调用了printf函数。这个函数是标准C库中的一个函数。每一个C语言的编译器都会提供。通俗的讲就是当你调用printf这个函数时,编译器就知道你要在屏幕上打印输出内容,它会将这行代码翻译成计算机可以理解的指令。这个printf函数在是在名为printf.o的文件中,这个文件是一个提前编译好的目标文件,连接器(ld)负责把hello.o 和 printf.o 进行合并,当然这个合并是要遵循一定规则的。正是因为链接器要对hello.o 和 printf.o 进行调整,所以 hello.o 才会被称之为可重定位目标文件,最终经过链接阶段可以得到可执行目标文件——hello
此时,得到的 hello 就可以被加载到内存中执行了
Why programmers need to understand how compilation system work?(为何程序员有必要理解编译系统是如何工作的?)
Reasons(原因):
- Optimizing program performance(优化程序性能)
- Understanding link-time errors(理解链接时出现的错误)
- Avoiding security holes(避免安全漏洞)
待补充:
对汇编、指令集、链接的引用
对三个原因的举例