我们了解过ASCII码,知道每个字符有对应的整数值,而 hello world 程序中每个字节为一个整数值,再对应成字符,像这样由ASCII组成的文件我们就称之为 文本文件 或者 二进制文件
这就是一个基本思想,系统中所有信息——磁盘文件,存储器的文件,网络上传输的数据都是一连串位表示的,而区分他们的唯一方法就是对象的上下文,不同的序列中一个同样的字节序可能表示一个整数,浮点数或者机器指令等等。
程序的翻译🤔
一个源文件的每一条语句都会被不同的程序转化成不同低级机器语言指令,然后按照一种被称为可执行目标程序的格式打包好,再以二进制磁盘文件的形式存起来。
编译器驱动程序读取源文件,并翻译成一个可执行目标文件,这个翻译过程其实就是
程序的编译问题(预处理,编译,汇编,链接),有点搞忘了就请移步我之前的博客,编译系统大致就是这样:
益处🤔
了解编译系统工作原理有啥好处啊?
- 优化程序性能
- 理解链接时出现的错误
- 避免安全漏洞
(感觉都很废话但又不能不要~) - 指令的理解🤔
计算机里,需要依靠处理器读取并解释储存在存储器里面的指令,此时源程序 hello.c 已经被翻译成了可执行目标文件 hello,并放在磁盘上。
系统的硬件组成🤔
要理解 hello 程序运行时发生了什么,就需要理解一个典型的系统硬件组织,我们以 Intel Pentium 产品模型为例,其他系统也有相同的外观和性能,这里不细讲因为有巨量的细节,书上也说了后面会细讲。
CPU 即中央处理单元,ALU 即算术/逻辑单元,PC 即程序计数器,USB 即通用串行总线
接下来就精炼的讲一讲一些基本概念呐:
1.总线
贯穿整个系统的一根电子管道,称作总线,作用就是携带信息并在各个部件之间传递,通常总线被设计传送定长字节的字节块,也就是字,字里面的字节数就是基本的系统参数,这就是为什么有我们之前讲到的32位机器字长4字节,64位机器字长为8字节。为了讨论方便,假设字长就是4,总线每次只传1个字。
2.I/O设备
即输入/输出设备,老四样还是键盘,鼠标,显示器以及存储数据和程序的磁盘驱动。
每个I/O设备会通过控制器或适配器与I/O总线相连,控制器和适配器之间的主要区别就是封装方式不同,前者位于设备本身或者主板的芯片组后者则是一个插在主板插槽上的卡。
3.主存
主存是一块临时存储设备,物理上讲就是一组动态随机存储存储器(DRAM)组成的,逻辑上讲就是一个线性的字节数组,每个字节都有其唯一的地址,地址从0开始,组成程序的每条机器指令都是由不同数量的字节构成的,因此,C程序变量相对应的数据项的大小是根据类型变化的,比如 int 需要4字节,short 需要2字节,double 需要8字节。
3.CPU
即中央处理器,是解释或执行存储在主存中指令的引擎。他的主要结构是一个字长的存储设备(或寄存器),称为程序计数器(PC),任何时刻PC都指向主存中的某条机器语言指令,即含有该指令的地址。
处理器会从计数器指向的存储器中读取指令,并解释其中的位,执行指令中的简单操作,然后更新计数器让他指向下一个指令,注意指令之间不一定相邻。
当然这种简单的操作并不多,还会围绕寄存器文件(一些1字长的寄存器组成),ALU(算术/逻辑单元,用于计算新的数据和地址)执行加载,存储,操作,跳转这些操作。
一句话,看上去只是指令集结构的简单实现,实际上是处理器使用了非常复杂的机制来加速程序运行。
高速缓存🤔
在 hello world 程序里,数据串初始是在磁盘上,然后复制到主存,最后从主存上复制到显示设备。从程序员的角度看,这些地址就是开销,减缓了程序“真正”工作。
上帝不会允许十全十美的东西出现,较大的存储设备比较小的运行的更慢,而高速设备的成本又十分的高,比如磁盘驱动器可能比主存大 1000 倍,但磁盘读取时间开销却是主存的 1*10^7 倍,因此更小更快的高速缓存存储器就应运而生了!
作为暂时的集结区域,用来存放处理器近期可能会处理的需要的信息,访问速度基本上与寄存器相媲美,这是位于处理器芯片的L1高速缓存,还有一个通过特殊总线连接到处理器的L2高速缓存,容量更大,访问时间是L1的5倍,但仍然比访问主存快 5-10倍。
L1和L2是依靠静态随机访问存储器的硬件技术实现的,现在比较新的系统甚至还有三级高速缓存,系统可以获得一个很大的存储器,同时访问速度也很快,原因是利用了高速缓存的局部性原理即程序具有访问局部区域的数据和代码的趋势。