程序是如何在电脑上运行的

对一个编程入门者来说了解程序的运行方式对学习编程来说是非常有帮助的。正所谓结构决定功能,这之前我们还需要了解支持其运行程序的物理层面的结构基础。

冯诺依曼结构

冯诺依曼结构
上图就是电脑结构的抽象示意图,我们将这样的结构称之为冯诺依曼结构。其中的输入设备和输出设备(统称为i/o)是非常好理解的,输入设备嘛就是鼠标键盘之类的,而输出设备就是屏幕,音箱之类。有些时候设备的分类也并不是那么清晰,比如打印机在打印时是输出设备,扫描时就是输入设备。这些不是本文的重点,我们要详细讲的是存储器。

存储器

按速度从快到慢排列分别是:寄存器>内存>硬盘

易失性存储设备:在电脑关机断电后所存储的内容会丢失的存储设备,往往速度较快(价格和速度成正比),但不能永久存储。非易失性存储则相反

寄存器

寄存器是cpu的一部分,在所有储存器中速度最快,成本也最高,所以量不大。每个寄存其都有自己的名称(比如AX,BX,CX,DX这些是通用寄存器),这些名字大多没有特殊的意义只是一个代号。其中一般可以存储64个2进制数。

内存

内存是一种易失性的存储设备,也就是电脑的内存条。我们可以将内存理解为一个表格,有两列地址(常表示为16进制数),和数据。是cpu可以直接访问的唯一设备(寄存器不算,应为它是cpu的一部分)

编程中以0x的数据是16进制数,这样做主要是为了区别于更常用的10进制数(不要加前缀)
类似的还有以0b前缀表示2进制数

地址 数据
0x7C00 23

这就表示在地址为十六进制数7C00的地方存储了一个十进制数23,电脑程序可以通过这个地址7C00来获取其对应的数据23。值得注意的是一个地址中可以存放的数据量是固定的并非无限大的(是电脑位数个2进制数)电脑的位数,就是我们常说的32位电脑和64位电脑的那个。我们可以通过公式2^ {n-1}(其中的n是电脑的位数,减1是因为第一个二进制数用来表示正负)来算出其最大可以存放的整数。对于32位电脑来说这个数是:2^ {32-1}=2^ {31}=2147483647

硬盘(也称作外存)

对于有些常识的读者来说硬盘的概念应该并不陌生。这是一种非易失性的存储设备,所有需要永久存储的数据如程序,文档都是存储在这里的。由于需要通过总线访问,所以速度相对较慢(在这里你不需要知道总线的含义)。

ps:以上概念都经过简化,于真实情况有些许差异


了解完了程序运行的结构基础,让我们来看看程序运行的过程

程序如何运行

起初程序被保存在硬盘中,当你用鼠标双击打开程序时操作系统会将程序按命令的执行顺序加载到内存当中(其实还有数据)。因为硬盘的读取速度相较于cpu的计算速度太慢,如不加载到内存中会拖慢程序的运行速度,而内存可以跟上cpu的运行速度。

在内存中命令按顺序存储(其地址是递增的),这看起来就像是一个代办清单。

地址 数据
0x01 从地址0x05 获取数据并存储到AX寄存器
0x02 从地址0x06 获取数据并存储到BX寄存器
0x03 将AX寄存器中的数据和BX寄存器的数据相加并放到AX中
0x04 让系统帮我输出AX寄存器中的值
0x05 1
0x06 1

以上是用人话写出的1+1的程序,看起来挺复杂的,但不要害怕,这模拟的是电脑最为底层的指令。我们日后要编写的程序比这高级很多,以上命令执行的功能只需要一行代码就能实现即print(1+1)

即使是人类面对上万项的代办清单是也不免会感到头大,电脑也一样。为了知道命令执行到了哪里,cpu使用一个寄存器“PC”来记录执行到了第几条命令。PC寄存器的值有cpu维护,程序无法修改,每运行一行命令就自动+1。
ps:PC这个名字是有意义的,它是Program Counter的缩写,翻译成中文就是程序计数器的意思