《计算机是怎样跑起来的》第四章 程序

推荐阅读:《计算机是怎样跑起来的》,通过一步步构造计算机,并且实现计算机功能进一步对计算机有所了解,对于有一定基础的人来说会有更清晰的认识。还有作者的另一本书《网络是怎样连接的》,还没看,但应该和这个风格一样,从0出发,一步步讲解,不是一般的僵知识点风格。

问题:

  • Flow Chart 的中文意思是什么?

  • 事件驱动是什么?

(1) 流程图(Flow Chart ) 是指用图的形式表示程序的流程。

(2)事件驱动——用户的操作等产生事件后,由事件决定程序的流程。
Windows 应用程序的运行时由事件驱动的。 例如选择 “打开文件” 菜单项就能打开一个窗口, 在里面可以指定要打开文件的名称和存储位置。 之所以能够这样是因为一旦触发了“选中了菜单项” 这个事件, 程序的流程就相应地流转了处理打开窗口的那部分。

本章重点


本章的主题是程序的流程。 程序员一般都是先考虑程序的流程再开始编写程序的。只有编写过程序的人才能体会到“程序是流动着的”。一个人编写的程序如果不能按照预期运行,就说明他还没有很好地掌握“程序是流动着的”这一概念。

为什么说“程序是流动着的”呢?因为作为计算机大脑的 CPU 在同一时刻基本上只能够解释、执行一条指令

把指令和作为指令操作对象的数据排列起来就形成了程序。请想象把若干条指令一条挨一条地依次排列到一条长长的纸带上。然后把这条纸带展开抻平,从顶端开始依次解释并执行上面的每条指令,这样看起来程序就好像流动起来了。这就是程序的流程。但是程序的流程并不是只有这一种。那么下面笔者就先介绍一下程序流程的种类吧。

CPU 就像流水线一样,一个时刻只能处理一个工作,而指令就是流水线上的产品一样,随着流动按顺序执行。(当然实际情况会更复杂)。

4.1 程序的流程分为三种

在之前学过:计算机的硬件系统由 CPU、I/O 和内存三部分构成。内存中存储着程序,也就是指令和数据。CPU 配合着由时钟发生器发出的滴答滴答的时钟信号,从内存中读出指令,然后再依次对其进行解释和执行。

CPU 中有各种各样的寄存器,其中有一个被称为 PC(Program Counter,程序计数器)的寄存器,负责存储内存地址,该地址指向下一条即将执行的指令。每解释执行完一条指令,PC 寄存器的值就会自动被更新为下一条指令的地址。

PC寄存器,这里的 P 是程序(Program)的 P,而 C 是计数(counter)的 C。

如果把 CPU 比作执行任务的组织团伙,PC寄存器就像一个传话人, 而内存就是组织的任务中心,CPU每次执行完一条指令,PC寄存器就指向内存中的下一条指令开始。它们每天的工作就像这样:

PC寄存器:这是你接下来要执行的指令,去吧。
CPU:交给俺。
几微秒之后,CPU结束了执行任务。
PC寄存器:这是你接下来要执行的指令,去吧
CPU:交给俺。
……

这就是不辞辛劳的寄存器与CPU之间的故事,它们微秒继微秒,是这个世界上最勤奋的楷模,计算机不断电,它们不放假。(泪目)。

PC寄存器的值在大多数情况下只会增加。

下面假设 PC 寄存器正指向内存中一个从 10 号地址开始的 3 字节指令。CPU 解释执行完这条指令后,PC 寄存器中的值就变成 10+3 = 13 了。也就是说,程序基本上是从内存中的低地址(编号较小的地址)开始,向着高地址(编号较大的地址)流下去的 。我们把程序的这种流动称为“顺序执行”(如图4.1 所示)。在这里插入图片描述
程序的流程总共有三种。除了顺序执行之外,还有“条件分支” 和 “循环”。

  • 顺序指令:按照指令记录在内存中的先后顺序依次执行的一种流程。
  • 条件分支:根据若干个条件的成立与否,在程序的流程中产生若干个分支的一种流程。
  • 循环:在程序的特定范围内反复执行若干次的一种流程。
    在这里插入图片描述

用流程图表示程序的流程

所谓流程图,正如其名,就是表示程序流程(Flow)的图(Chart)。有很多专业的程序员,他们在编写程序前,都会通过画流程图或是类似的图来思考程序的流程。在这里插入图片描述
流程图的方便之处在于它并不依赖于特定的编程语言。

流程图的画法在此省略。

4.4 结构化程序设计

结构化程序设计是由学者戴克斯特拉提倡的一种编程风格,简单地说,所谓结构化程序设计就是“为了把程序编写得具备结构性,仅使用顺序执行、条件分支和循环表示程序的流程即可,而不再使用跳转指令”。

大家耳熟能详的 goto语句。应该在学习的时候听到很多人说过尽量不要用,因为跳转指令的会使程序陷入到流程错综复杂的状态。在这里插入图片描述
在程序设计的世界中,如果看到了以“结构化”开头的术语,就可以这样认为:程序的流程是由程序块表示的,而不是用 GoTo 语句等跳转指令实现的。例如,微软的 .NET 框架所提供的新版 BASIC 语言Visual Basic.NET 中,就以增加新语法的方式加入了被称作“结构化异常处理”的错误处理机制。这里所说的异常类似于错误。

在旧版本的 Visual Basic 中,一旦发生了错误,程序的流程就会跳转到执行错误处理的地方。用程序块来表示这种错误处理方式的机制,就是结构化异常处理。在 Visual Basic.NET 中,用 Try~Catch~EndTry 程序块来表示结构化异常处理(如代码清单 4.4 所示)

但是即使使用了结构化异常处理,在硬件上使用的也还是跳转指令,只是说在高级语言中不用再写相当于跳转指令的语句了。

如果把用高级语言所编写的程序转换成机器语言,像结构化异常处理这样的语句还是会被转
换为跳转指令.

在这里插入图片描述

4.5 画流程图来思考算法

思考算法时的要点是是要分两步走:

  • 先从整体上考虑程序的粗略流程
  • 再考虑程序各个部分细节的流程。

先来看看粗略的流程:

在这里作者介绍了一种粗略的流程。这是一种相当简单的流程,虽然或多或少会有例外,但是几乎所有的程序从整体来看都具有一个一成不变的流程,那就是“初始化处理”→“循环处理”→“收尾处理”。

请试想,用户是怎样使用程序的呢?首先,用户启动了程序(程序执行初始化处理)。接下来用户根据自己的需求操作程序(程序进入循环处理阶段)。最后用户关闭了程序(程序执行收尾处理)。这样的使用方法就可以直接作为程序的整体流程。

4.6 特殊的程序流程——中断处理 重点

从前的日色变得慢,车、马、邮件都慢,一生只够爱一个人。 后来,有了中断。

中断的知识点比较多,很有必要学习,这本书中讲的比较粗略。

稍微介绍一下两种特殊的程序流程——中断处理和事件驱动(Event Driven)。首先说明中断处理。

中断处理 是指计算机使程序的流程突然跳转到程序中的特定地方,这样的地方被称为中断处理例程(Routine)或是中断处理程序(Handler),而这种跳转是通过 CPU 所具备的硬件功能实现的。

人们通常把中断处理比作是接听电话。假设诸位都正坐在书桌前处理文件,这时突然来电话了,诸位就不得不停下手头的工作去接电话,接完电话再回到之前的工作。像这样由于外部的原因使正常的流程中断,中断后再返回到之前流程的过程就是中断处理流程。

在第 2 章微型计算机的电路图中已经展示过,在 Z80 CPU 中有INT 和 NMI 两个引脚,它们可以接收从 I/O 设备发出的中断请求信号A 。

以硬件形式连接到 CPU 上的 I/O 模块会发出中断请求信号,CPU根据该信号执行相应的中断处理程序。在诸位使用的个人计算机上,中断请求信号是由连接到周边设备上的 I/O 模块发出的。例如每当用户按下键盘上的按键,键盘上的 I/O 模块就会把中断请求信号发送给CPU。CPU 通过这种方式就可以知道有按键被按下,于是就会从 I/O设备读入数据(如图 4.14 所示)。CPU 并不会时刻监控键盘是否有按键被按下。(这就是好处,不需要时刻监控)在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

中断处理以硬件发出的请求为条件,使程序的流程产生分支,因此可以说它是一种特殊的条件分支。

可以理解为: if (受到某个中断请求) 执行请求。

可是,在诸位编写的程序中并不需要编写有关中断处理的代码。因为处理中断请求的程序,或是内
置于被烧录在计算机 ROM 中的 BIOS 系统(Basic Input Output System,基本输入输出系统)中,或是内置于 Windows 等操作系统中。诸位只需要先记住以下两点即可:计算机具有硬件上处理中断的能力;中断一词的英文是 Interrupt。

4.7 特殊的程序流程——事件驱动

程序员们经常用事件驱动的方式编写那些工作在 GUI(GraphicalUser Inteface,图形用户界面)环境中的应用程序,例如 Windows 操作系统中的应用程序。这听起来好像挺复杂的,但其实如果把事件驱动想象成是两个程序在对话,理解起来就简单了。

下面来看一个实际的例子:

代码清单 4.5 中列出了一段用 C 语言编写的 Windows 应用程序,这里只列出了程序的骨架。

在程序中有WinMain()WndProc() 两个函数(代码块)。

WinMain() 是在程序启动 时被调用的主例程(Main Routine)。
而 WndProc() 并不会被诸位所编写的程序本身调用,Windows 操作系统才是 WndProc() 的调用者。这种机制就使得 Windows 和诸位所编写的应用程序这两个程序之间可以进行对话在这里插入图片描述

事件(Event):通常把用户在应用程序中点击鼠标或者敲击键盘这样的操作称作“ 事件 ”。

负责检测事件的是 Windows。Windows 通过调用应用程序的 WndProc() 函数通知应用程序事件的发生。而应用程序则根据事件的类型做出相应的处理。这种机制就是事件驱动。

可以说事件驱动也是一种特殊的条件分支,它以从 Windows 送来的通知为条件,根据通知的内容决定程序下一步的流程。

if (事件发生) {
	Window 检测到事件
	通过 WndProc() 函数通知应用程序事件的发生
	应用程序根据事件的类型作出相应的处理
}

要实现事件驱动,就必须把应用程序中的 WndProc() 函数(称为窗口过程, Window Procedure) 的起始内容地址告诉 Windows。这一步将在应用程序 WinMain() 中作为初始化处理被执行。

程序启动, WinMain() 开始
在 WinMain()中,实现将应用程序中 WndProc() 函数的起始内存地址告诉 Windows的操作。

事件驱动是一种适用于 GUI 环境的编程风格,在这种环境中用户可以通过鼠标和键盘来操作应用程序。

也许读完中断处理和事件驱动的这两节,诸位会觉得稍微有些混乱,但是程序的流程还是只有顺序执行、条件分支和循环这三种,这一点是没有改变的。

其中的顺序执行是最基本的程序流程,这是因为CPU 中的 PC 寄存器的值会自动更新。条件分支和循环,在高级语言中用程序块表示,在机器语言和汇编语言中用跳转指令表示,在硬件上是通过把 PC 寄存器的值设为要跳转到的目的地的内存地址来实现。只要能充分理解这些概念就 OK 了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值