第一章:学习前置知识
第二节:计算机概况
作为程序员,我们所写的程序,最终由计算机来执行,那么对计算机有一定的了解,肯定有利于我们对于C语言的学习,甚至可以说,对计算机的了解,是学好C语言所必须的。(想升官就要琢磨领导,想泡妞就得琢磨女人,你说呢)
首先要提计算机,不得不提一个人,这个人就是冯.诺依曼。这个是个牛人,不过他总结的诺依曼体系,就那么回事,如下:
有内存,有中央处理器,有控制器,有输入输出。程序要执行,先由外设I/O模块读入内存memory,然后由cpu从内存中读取,执行结果再保存到内存。
我在这里多哔哔两句 ,诺依曼总结出的这个体系,其实当时有很多人能总结出来,所以我说这个体系也就那么回事(这是我自己认为的,不同意没关系)。但为啥就叫冯.诺依曼体系,咋不叫毛哥体系呢?因为诺依曼太牛了,啥好事都往他身上贴。诺依曼体系架构容易搞出来,而搞出来就以他的名字命名,恰恰说明这个人有多牛(冯.诺依曼是数学家)。
为了说明这个体系,还要有一个图:
第一个图,一堆数据从左边进入,经过中间的盒子,被加工成另外一堆数据,叫结果。首先,这个盒子的功能是单一的固定的。只要左侧给定数据,经过盒子,结果也就给定。是不是像一个函数?给定自变量,那么函数结果就确定了呢?
但这个盒子功能单一,用处不大,例如只能执行加法运算。于是,我们可以发明一个复杂的盒子(盒子里面装了很多功能或者函数),见第二个图。通过控制信号control signals,我们可以选定一个特定的功能或者函数。这个时候,输出结果由数据(data)和选定的函数决定。我们给定连续的一系列数据,连续的一系列控制信号(控制信号可以由instruction code 指令码来转换得到),或者指令码,只要配合好,我们就能得到一系列固定的输出。这就形成了程序流。
这样,就诞生了计算机中的运算单元和控制单元。运算单元包括指令解释(instruction interpreter)和运算(General-purpose arithmetic and logic functions)单元,而控制单元必须让数据data和运算data的指令产生的信号signals同时作用于运算单元上,才能产生正确的结果。
现在,我们要使用这个机器,需要手动将数据和指令输入到机器中,然后再手动取出执行结果(最早的计算机确实是这么做的)。如果输入过程中,产生任何错误,就必须重来。如果我们想修改一下数据,指令不变,也必须全部重来。是不是很麻烦?
这个时候,我们可以找一个存储器,也就是main memory。先把指令和数据放到这个main memory(这个main memory我们叫内存)里面。如果只修改输入数据,那么我们可以在内存中对应位置进行修改,其他地方就不动了,修改好以后,只要重新执行内存中的程序就可以得到结果。方便很多了吧。
现在好像方便了,但是把数据和指令放在内存和计算结果的取出,还是要手动,也很麻烦,再做个机器,把输入输出的活也干了,这个就是输入输出这单元,负责将指令和数据装入内存,负责计算结果的取出。
这时整个机器的控制单元任务就多了,控制单元必须协调其他几个单元的工作,例如指令和数据装入内存,结果的取出等。这些操作最终也变成了中央处理器所需要完成工作的一部分。
大家思考一个问题,将数据和指令装入内存(数据和指令合起来可以称为一个程序),需要程序通过中央处理器来完成这个工作。而中央处理器要完成这个工作,只能通过一段程序来完成,是不是矛盾了。要把程序装入内存,装入程序的程序就必须先在内存中,那么谁又来负责装入程序的程序的装入工作呢?(这段话很绕,其实就是一个事物的存在必须以自己已经存在为前提,就是先有鸡还是先有蛋的问题)。
解决方案有两个,一个是我们在作内存的时候,事先将这段程序做到内存中,这段程序的功能是:从外部设备指定位置来读取一段外部设备中的程序到内存,并执行这个程序。还有一种就是可以在内存已经装入到计算机以后,通过特殊设备,将这段程序在放到内存中。当然,这段程序放入以后,就永远停在内存里面,不会被改动,也不能被改动了。
现在这个问题就解决了,当计算机启动的时候,首先执行这段内存中已经存在的程序,这段程序的工作就是从外部设备指定位置读取一段程序,然后执行这段被读取的程序。
这段外部设备中存在的程序,我们事先做好,让他做我们想做的工作。好了,到这里整个计算机就可以跑起来了,替我们干活了。
总结一下上面的过程,我们发现计算机的几个主要组件:内存,中央处理器,控制器,外部输入输出设备。是不是就是冯.诺依曼体系的要求。
对照现实世界的计算机,就你面前的台式机。键盘,鼠标和显示器就是输入输出设备,而机箱里面就是内存,中央处理器也就CPU等设备。
程序执行的过程就是,CPU把程序从硬盘装入内存,执行完毕后,把结果送到显示器。而计算机要执行那些程序的指令,由你的键盘和鼠标发送给CPU。
简单吧,好像没啥难的。