1.1.1 换个角度看计算机
之所以要探究计算机系统的内部结构和工作原理,是为了能够准确地把握代码指令的传递和处理流程,找出限制和降低程序运行效率的关键点所在,从而让程序员能够跟随计算机一同思考,并编写出高效、可靠的代码。要了解计算机系统的内部结构和工作原理并不容易,它至少涉及三门独立的科目:计算机组成原理、计算机操作系统和编译原理。这些都是计算机专业的学生必修的主要课程。但即使将它们逐个学完,若不能加以贯穿和联系,那么一个系统化的知识框架就没办法成功地搭建起来,于是学习成果和功效就会被打折!从程序设计和代码编写的角度将上述知识有机地串接起来是一个不错的主意。
作为一个程序员或者开发人员来说,完全掌握上述科目的知识也实在是一件劳心费神的事,何况似乎掌握了它们也不见对程序开发起到什么明显的推进作用。那这个矛盾该如何解决呢?很简单,就是以程序员最熟悉的方式来诠释这些基础的理论知识。如果能从简单的代码编写出发,思考编译器的工作机制,进而探究计算机系统的工作原理和组织结构,这是一件多么有趣的事情啊!当程序员通过代码编写这一主线将整个流程走完时,一方面,他们可以对计算机系统有一个深入的理解;另一方面,这种理解将反作用于程序设计实践,提高程序员的编码能力,使他们足以写出漂亮、高效的代码。这就是我们所希望做到的。帮助读者走完这一流程的第一步就是先向读者介绍一些基本的概念和必要的准备知识,其中最基础的就是对计算机系统有一个概括的认知。这当然不同于一般的计算机文化基础或者计算机入门知识,我们假设读者都不是“电脑盲”。所谓的对于计算机系统的概括的认知,更重要的是侧重于计算机中指令的传递过程,也就是跟程序运行直接相关的硬件设备,诸如外设之类的硬件则不在我们考虑的范围之内。
首先想请问大家一个问题,什么是电子计算机呢?大家一定认为这是一个非常简单而容易的问题,然而尽管大家经常使用计算机,但要给出电子计算机的准确定义也未必像想象中那么容易。电子计算机是根据程序化的指令来执行具体任务,集合输入、处理、存储和输出功能于一身的一种电子机器。
通常一个用户与计算机之间的交流过程需要经过几个必要的环节,这个过程如图1-1所示。在这个过程中,用户是不能直接操作计算机硬件的,和用户真正直接打交道的是各式各样的应用软件,如文字处理软件、游戏软件或者图像处理软件等。然而,应用软件通常也不能直接和计算机硬件进行交流,应用软件必须在由操作系统提供的环境下才能正常运作。操作系统是控制其他程序运行、管理系统资源并为用户提供操作界面的系统软件的集合,它是计算机系统的内核与基石,负责管理和协调计算机的软、硬件资源。操作系统是一个非常庞大的管理控制程序,大致包括5个方面的管理功能:进程与处理机管理、作业管理、存储管理、设备管理和文件管理。目前计算机上常见的操作系统有Windows、UNIX、Linux等,操作系统负责和硬件进行交互。这样我们可以看到一条清晰的脉络:用户→应用软件→操作系统→硬件设备。
图1-1 用户与计算机的交互
程序员所编写的软件可能是具体的应用软件,可能是操作系统,当然也可能是更底层的硬件驱动程序,这里我们假设操作系统已经集合了硬件驱动程序。无论是应用软件还是操作系统,都是用计算机语言编写的。这是一件奇妙的事情,简单的符号组合怎样钩织出美轮美奂的软件世界呢?计算机硬件又是如何运行软件的呢?如果读者是一个资深的程序员,他一定不会感到奇怪,反正程序代码经过编译器编译就自然而然地变成软件了。但是编译器是如何做到这一切的呢?计算机硬件又是如何解读和执行编译器生成的目标代码的呢?能够回答这些问题的人可能不多了。多数人只不过是只知其一,不知其二,浅尝辄止,蜻蜓点水。但也许会有人这样想,反正会编程就行了,又何须管它编译器如何工作呢?这就是高手与菜鸟的区别!如果连编译器的工作流程和计算机的系统原理都不甚清楚,写出高效的程序代码根本就无从谈起。
编译器也是软件,操作系统也是软件。有人用C++语言在Visual C++环境下写了一个小程序就自以为是、沾沾自喜,那么他有没有想过Visual C++是如何被写出来的呢?Visual C++运行在Windows操作系统环境下,那么再进一步追问,操作系统是怎样被写出来的呢?著名的Linux操作系统最初的版本就是由芬兰人李纳斯•托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的,李纳斯不愧为真正的天才程序员。我们不可能要求所有的程序员都能写出操作系统内核,正所谓“闻道有先后,术业有专攻”嘛。但是一个真正的程序设计高手应该至少能够读懂一个编译器程序的内核,至少能够读懂一个操作系统的内核。这个要求并不苛刻!当你真正能够理解编译器的行为方式,以及计算机系统的运作机制时,你已然一跃成为一个程序设计高手了。