1. 程序是什么?
程序是由指令和数据组成的。
当我们使用计算机运行一个程序时,计算机会读取程序中的指令一步步执行,直到达到程序结束的地方。
-
程序的指令:就像一份菜谱,告诉计算机按照哪些步骤来做事情。
-
程序的数据:就像菜谱中需要的材料一样,程序需要一些数据才能够按照预期的方式运行。
2. CPU中的寄存器
上一章中说了CPU的组成部分:
CPU的内部由寄存器、控制器、运算器和时钟四个部分构成,各部分之间由电流信号相互连通。寄存器可用来暂存指令、数据等处理对象,可以将其看作是内存的一种。根据种类的不同,一个CPU内部会有20~100个寄存器。控制器负责把内存上的指令、数据等读入寄存器,并根据指令的执行结果来控制整个计算机。运算器负责运算从内存读入寄存器的数据。时钟负责发出CPU开始计时的时钟信号。
CPU是具有各种功能的寄存器的集合体,对于程序员来说只需要了解寄存器就可以了!因为程序指令是通过寄存器来描述的。
- 程序实现的是将100和200两个数值相加,并将结果输出到显示器上。
寄存器的种类有很多,这里列举对程序员理解程序来说最重要的几种。
种类 | 功能 |
---|---|
程序计数器 | 存储下一条指令所在内存的地址 |
累加寄存器 | 存储执行运算的数据和运算后的数据 |
标志寄存器 | 存储运算处理后的CPU的状态 |
通用寄存器 | 存储任意数据 |
3. 程序的流程
程序的流程分为三种,顺序执行,条件分支、循环。
决定程序流程的是程序计数器。
3.1 顺序执行
假设程序加载到内存后存放的位置是从0100~0106, CPU执行0100地址的指令后,程序计数器的值就变成了0101((当执行的指令占据多个内存地址时,增加与指令长度相应的数值),然后,CPU的控制器就会参照程序计数器的数值,从内存中读取命令并执行。也就是说,程序计数器决定着程序的流程。
- 示例中的程序实现的是将100和200两个数值相加,并将结果输出到显示器上。
实际上每一条指令可能存储在多个地址上,类似如下:
3.2 条件分支
程序运行的开始位置是0100地址。随着程序计数器数值的增加,当到达0102地址时,如果累加寄存器的值是正数,则执行跳转指令(jump指令)跳转到0104地址。此时,由于累加寄存器的值是100,为正数,因此0103地址的指令被跳过,程序的流程直接跳转到了0104地址。也就是说,“跳转到0104地址”这个指令间接执行了“将程序计数器设定成0104地址”这个操作。
- 这里程序计数器的数值 从 0102 直接变化为 0104。
3.3 循环执行
程序执行到0102地址时,如果累加寄存器的值小于0,跳转到0105地址。如果累加寄存器的值大于0,执行0103 0104的地址的指令,注意0104的地址的指令是又跳转到0102地址。所以就产生循环了!
- 刚开始累加寄存器的值是2,一次循环减1,第二次循环结束后,变成0。
- 程序计数器数值 0102→0103→0104 变化了两次。
条件分支和循环中使用的跳转指令,会参照当前执行的运算结果来判断是否跳转。
CPU在进行运算时,标志寄存器的数值会根据运算结果自动设定。条件分支在跳转指令前会进行比较运算。至于是否执行跳转指令,则由CPU在参考标志寄存器的数值后进行判断。运算结果的正、零、负三种状态由标志寄存器的三个位表示。
3.4 函数的调用机制
函数的调用也是通过把程序计数器的值设定成函数的存储地址来实现的。
和条件分支、循环不同的是:函数的调用需要在完成函数内部的处理后,处理流程再返回到函数调用点(函数调用指令的下一个地址)。
- 通过跳转指令把程序计数器的值设定成1001实现对add函数的调用。
- 函数执行完成后再通过跳转指令把程序计数器的值设定为0103,继续原函数的流程。
4. 总结
程序是由指令和数据组成的,程序是在内存中被CPU执行的。程序执行的流程是通过程序计数器来完成的。
关注微信公众号:“小虎哥的技术博客”,让我们一起成为更优秀的程序员❤️!
文章和代码仓库:
gitee(推荐):https://gitee.com/cunzaizhe/xiaohuge-blog
github:https://github.com/tigerleeli/xiaohuge-blog