奎克的藏经阁 · MinerU 解析内容

编码 隐匿在计算机软硬件背后的语言

438 个 PDF 物理页 · 本页显示文件第 411–420 页

PDF 物理页索引 410

文件中的第 411 页 · 印刷页码:394

在程序设计中有一种现象:如果让100个人来编写输出素数的程序,你可能会得到100个不同的解决方法。就算所有的程序员都使用“爱拉托逊斯筛法”来解决这个问题,其最后所写的程序也不一定与本文所写程序完全相同。如果说程序设计是一门科学,那么就不应该出现如此多的解法,而不正确的方法将会非常明显。偶尔,一个程序设计问题会诱发出极富创造性的火花或洞若观火般的觉察力,这就是所谓的程序设计的“艺术”。但是,程序设计的更多的时候是设计和建造,就像修建一座大桥的过程。

早期的程序设计对编程人员的要求很高,所以很多早期的程序员都是科学家或工程师,他们通常利用FORTRAN或ALGOL中的数学算法来描述并解决各自领域的问题。回顾程序设计语言发展的整个历程时,我们会发现,人们一直在努力开发一种能为更大范围的人群所使用的语言。

第一个成功地为商务系统所使用的程序设计语言是 COBOL(COmmon BusinessOriented Language),今天它仍然被广泛使用。COBOL于1959年开始开发,由美国工业界和国防部组成的委员会发起并实施,它的设计思路受到格瑞斯·霍珀早期编译器的影响。从某些方面来看,COBOL的设计中渗透了这种思想:使管理人员—可能并不进行实际的编码工作—但他们至少可以看懂程序代码,而且能够检测程序能否完成预定工作(实际上这种情况非常少见)。

COBOL语言广泛支持读取记录(record)和生成报表(report)。记录是按照统一方式归类整理的信息的集合。例如,保险公司一般会维护一个包括其所售的所有保险信息的大型文件,每一项保险业务称为一条单独的记录。每一条记录包括客户的姓名、出生日期等信息。早期编写的COBOL程序,大都是为了处理存储在IBM打孔卡片上的80列记录而编写的。为了尽量减少孔洞所占用的卡片空间,年份通常设计成2位而不是4位,随着时间的推移,这个设计的缺陷逐渐显露出来,最终导致在2000年出现了著名的“千年虫问题”(millennium bug)。

编码隐匿在计算机软硬件背后的语言

394

PDF 物理页索引 411

文件中的第 412 页 · 印刷页码:395

在20世纪60年代中期,为了配合System/360项目的开发,IBM同时开发了程序设计语言 PL/ I(I 是罗马数字中的 1,因此 PL/ I 的含义是:Programming Language NumberOne)。PL/I的设计者们想要使其融合ALGOL的块结构,FORTRAN语言的数学函数功能以及COBOL处理记录和报表的能力,但该语言却远没有达到FORTRAN和COBOL那样广泛的使用程度。

虽然FORTRAN,ALGOL,COBOL以及PL/Ⅰ都可以应用于家用计算机,但它们对于小型计算机的影响远没有BASIC语言那么深远。

BASIC(Beginner's All-purpose Symbolic Instruction Code)由达特茅斯(Dartmouth)大学数学系的约翰·克莫尼(John Kemeny)和托马斯·克鲁兹(Thomas Kurtz)在1964年开发,该语言最初是为达特茅斯分时系统而设计的。达特茅斯大学的学生并非数学或工程专业,因此他们不应该为打孔卡片和复杂的程序语法花费太多精力,他们要做的只是端坐于计算机终端前,在数字后面输入一些BASIC语句来完成编程。BASIC语句前的数字用来指明该语句在程序中的次序。前面没有数字的语句是系统命令,如 SAVE(将BASIC程序保存至磁盘),LIST(按顺序显示行)以及RUN(编译并运行程序)。BASIC手册的第一版中的第一个程序是这样的:

与ALGOL语言不同,BASIC不要求程序员指定变量的存储类型,究竟一个变量是保存为整型还是浮点型并不需要程序员担心,大部分数默认都是以浮点数格式存储的。

很多BASIC的后续版本都是解释型(interpreter)而不是编译型(compiler)。如前所述,编译器读取源文件并生成一个可执行文件;而解释器却采取边读边执行的方式,不会产生新的文件。解释器比编译器的原理简单一些,因此更容易编写,但其运行程序的速度要比后者要慢。BASIC语言应用于家用计算机的时间较晚,1975年,比尔·盖茨(BillGates,生于1955年)和其好友保罗·艾伦(Paul Allen,生于1953年)为Altair 8800编写了BASIC解释器,这一事件可以视为BASIC在此领域的开端,同一年他们创建了微软公司(Microsoft Corporation)。

Pascal程序设计语言继承了ALGOL的大部分结构,同时还继承了COBOL的记录处理功能,它由瑞士计算机科学教授尼尔莱斯·沃思(NiklausWirth,生于1934年)在20世纪60年代末开发完成。IBM PC的程序员对 Pascal非常青睐,而备受欢迎 Pascal版本却是大名鼎鼎的 TurboPascal。1983年,宝兰公司(Borland International)发布了TurboPascal,当时的售价是49.95美元。Turbo Pascal由一名叫安德斯·海尔斯伯格(AndersHejlsberg,生于1960年)的丹麦大学生开发,它提供了完整的集成化开发环境(integrateddevelopment environment)。程序的文本编辑器和编译器集成在一起,这样就方便了程序的调试和运行,大大加快了程序开发速度。集成化开发环境以前主要用于大型计算机,TurboPascal实现了在小型计算机上的突破。

24 高级语言与低级语言

395

PDF 物理页索引 412

文件中的第 413 页 · 印刷页码:396

Pascal对Ada的影响也非常大。Ada是为美国国防部开发应用的一种语言,它以奥古斯塔·艾达·拜伦(AugustaAdaByron)命名。在第18章曾提到过,奥古斯塔·艾达·拜伦是查尔斯·巴贝芝的解析机发展历程的记录者。

接下来就是C,一种深受喜爱的程序设计语言。C语言主要是由贝尔电话实验室的丹尼斯·M·里奇(DennisM.Ritchie)开发的,从1969年开始设计并于1973年开发完成。人们常常对为什么以C来命名该语言感兴趣,答案其实很简单,它是一种早期的程序设计语言 B的后继者。B 是 BCPL(Basic CPL)语言的一种精简版本,而 BCPL来源于CPL( Combined Programming Language )。

如第22章所述,UNIX操作系统在设计的过程中充分考虑到了可移植性。当时的许多操作系统都是基于某种处理器的,并且使用汇编语言编写,基本上没有可移植性可言。1973年,UNIX采用C语言编写(更准确地说,应该是重写)成功,从此以后UNIX操作系统和C语言就变得密不可分了。

C 是一种风格非常简洁的语言。例如,ALGOL 和 Pascal 使用关键字 begin 和 end 来界定程序块,而在C中这两个单词被一对大括号“{}”取代。下面给出一个例子,程序员常常会把一个常量和一个变量相加,比如:

i = i + 5;

在C程序中,你可以将上面的语句简写为:

$$
\mathrm { ~ \bf ~ i ~ } + = \mathrm { ~ \bf ~ 5 ~ } ;
$$

如果只需要把变量加1(即增量),则该语句还可以精简成下面这样:

编码隐匿在计算机软硬件背后的语言

396

PDF 物理页索引 413

文件中的第 414 页 · 印刷页码:397

i++;

在16位或32位微处理器中,i++这种语句仅需要一条机器码指令就可以执行。

在本章的前面曾讲过,很多高级语言都不支持移位操作和按位布尔运算操作,而许多处理器其实支持这类操作,C语言打破了这种局限,它广泛地支持这类运算。除此之外,C语言的另一重要特征是对于指针(pointer)的支持,指针本质是数字化描述的内存地址。C 语言中的很多操作与通用处理器的指令非常相似,因此C也被称为高级汇编语言(high-level assembly language)。与类 ALGOL语言相比,C的操作集与通用处理器的指令集接近程度更高,或者说远胜过它们。

但是,所有的类ALGOL语言——即大多数常用程序设计语言———其设计模式都是基于冯·诺依曼计算机体系的。设计一种非冯·诺依曼体系的程序设计语言并非易事,而让人们接受并使用这种语言则更加困难。LISP(List Processing)是一种非冯·诺依曼体系程序设计语言,它主要应用于人工智能领域,由约翰·麦卡锡(JohnMcCarthy)在20世纪 50年代末期开发完成。APL(A Programming Language)是另一种全新的语言,与LISP完全不同,它同样完成于20世纪50年代末期,由肯尼斯·艾佛森(KennethIverson)开发。APL的特殊之处在于,它使用一个特殊的符号集,利用其中的符号可以一次性对整个数组里的数字完成操作。

类ALGOL语言一直在程序语言领域占据着重要地位,而且近年来,此类语言在一些方面进行了改进,导致面向对象程序设计语言(object-orientedlanguage)的产生。面向对象语言主要应用在图形化操作系统中,我们将会在下一章(也是最后一章)介绍这种操作系统。

24 高级语言与低级语言

397

PDF 物理页索引 414

文件中的第 415 页 · 印刷页码:未识别

图形化革命

对于《生活》(life)杂志的读者而言,1945年9月10日这一天的杂志像以往一样,有很多习以为常的文章和照片:第二次世界大战结束的相关新闻;讲述舞蹈家瓦斯拉夫·尼金斯基(VaslavNijinsky)在维也纳生活的点点滴滴;主题为美国汽车工人的图片新闻。但同时,在这一期的杂志中还有些不寻常的内容:万尼瓦尔·布什(VannevarBush1890-1974)发表了一篇关于未来科学大胆猜想的文章。万·布什(人们常这样称呼他)的发明与贡献对计算机历史产生了深远的影响其中最著名的就是他设计开发具有划时代意义的模拟计算机——微分分析器(The Differential Analyzer)—1927\~1931年,当时万·布什在担任麻省理工学院(以下简称为MIT)工程学教授期间发明了这个机器。这篇文章在杂志上发表的时候,也就是1945年,布什所担任的职位是科学研究及开发办公室(Office of ScientificResearch and Development,OSRD)的主任,负责美国战时科研活动的协调工作,其中就包括了曼哈顿计划(ManhattanProject)。

万·布什将自己两个月前在《大西洋月刊》(TheAtlanticMonthly)上发表的一篇文章,通过浓缩精简,重新发表在《生活》杂志上,并将这篇文章最终取名为《思维之际》(AsWeMavThink),文中描述了一种未来的发明,这项发明可以帮助科学家和研究人员更轻松地处理日益增多的技术期刊及文章。布什提出可以利用微缩胶片作为解决方案,同时他构想出了一种叫做麦克斯储存器(Memex,又名记忆扩展器)的设备,它可以对书籍、文章、录音和图片进行保存。麦克斯储存器还有一项重要的功能,那就是它可以让用户根据某个主题在所有的素材之间建立起关联,这些关联的基本来源就是我们人类的思维。他还大胆预言一种新的职业群体,他们的工作就是在繁杂的信息载体之间提炼并建立起可靠的关联。

PDF 物理页索引 415

文件中的第 416 页 · 印刷页码:399

在20世纪的那个年代,讲述辉煌未来的文章屡见不鲜,但《思维之际》这篇文章却异常耀眼。它所讲述的不是可以替代我们去做家务劳动的设备,也不是关于未来运输方式或智能机器人的故事,这个故事的主角是信息(Information),故事的主线是如何利用新技术成功的处理信息。

回顾历史,从第一台继电器计算器出现到现在为止,65年过去了,计算机的体积越来越小,处理速度越来越快,价格也越来越便宜。这一趋势极大地改变了计算的原始属性。当计算机价格变得很便宜,可以实现人手一台;当计算机体积越小、处理速度越快,软件就能发挥更大的作用,而机器就可以承担越来越多的工作。

要充分利用日益增长的运算和处理能力,较好的一种方法就是不断改进计算机系统中的关键部位,最典型的就是用户界面(UserInterface)它可以看作人机交互的轴心。人与计算机是两种完全不同形式的“客观存在”,只可惜在人机交互的这个过程中,与其让计算机去适应人类的特性,远不如劝服人们进行调整以适应计算机的特性来得容易。

在计算机发展早期,交互式这个概念并没有它的实际意义。人们编程时更多使用的是开关和电缆,有一部分人使用的是打孔纸带或胶片。到了20世纪50到60年代(有些观点认为这一时间可以延续到70年代)计算机已经可以使用批处理(batchprocessing)进行编程:程序和数据被“分布”在打孔卡上,然后一次性录入到计算机内存。这些工作完成之后,再由程序对数据进行分析,得出结论,最后将结果打印在纸上。

最早的交互式计算机运用的是电传打字机。我们回忆一下前面讲过的达特茅斯(Dartmouth)时分操作系统(原型出现于20世纪60年代早期),这种系统支持多个电传打字机同时工作,而且互不影响。此类系统中,用户在打字机上输入一行,计算机会相应地输出一行或多行。通常,打字机和计算机之间的信息交流是由一串ASCI码(也有可能是其他字符集)来完成的,这些ASCII码大多由字符编码组成,当然还包括像回车、换行等一系列简单的控制字符编码。随着机器的运行,相应的事务也随着打印纸的旋转逐步推进。

25 图形化革命

399

PDF 物理页索引 416

文件中的第 417 页 · 印刷页码:400

阴极射线管(cathode-ray tube,CRT,这是20世纪70年代随处可见的设备)并不受这类限制。使用软件来协调整个屏幕显得更加灵活方便一这可以算得上是一种二维的信息平台。但是为了尽量保持操作系统显示输出的逻辑一致性,早期那些为小型计算机编写的软件都把CRT显示器看做“玻璃屏幕电传打字机”—所有内容都是一行一地显示的,当字符排到底端,屏幕被填满时,屏幕上的内容要整体向上翻滚。除了CP/M(微处理机操作系统)中的所有工具软件之外,大部分MS-DOS下的工具软件都采用这种方法它们都仿照电传打字机的工作方式来使用视频显示器。使用电传打字机这种工作原理的操作系统有很多,或许UNIX才算是最典型的原型操作系统之一,它还一直保留着这种“传统工艺”。

不巧的是,ASCI码字符集不完全适用于阴极射线管的工作方式。在最原始的ASCII码设计中,编码1Bh被标识为Escape,它的主要作用是帮助字符集进行扩充。在1979年,美国国家标准协会(American National Standards Institute,ANSI)发布了一项题为“ASCII码使用的附加控制(Additional Controls for Use with American National Standard Code forInformation Interchange)”的标准。该标准发布的初衷是为了“适应二维字符-图像设备输入输出控制中迫在眉睫的相关需求,其中包括阴极射线管和打印机之间的交互终端………”

其实Escape的编码1Bh只占据一个字节,且它的含义是唯一的。Escape如果作为一串序列的前缀字符,那么这串字符序列的含义也随之改变。比如下面这串序列:

1Bh 5Bh 32h 4Ah

可以看出Escape编码随后紧跟的是字符“[”“2”“J”的 ASCI码,现在这一串字符的含义为“清屏”然后移动光标至左上角。这种定义在电传打字机上是不可能出现的。下面这串序列:

1Bh 5Bh 35h 3Bh 32h 39h 48h

即Escape编码随后紧跟的是字符“[”、“5”、“;”、“2”、“9”、“H”,这串字符的作用是把光标移到第5行的第29列。

键盘和CRT一起对远程计算机传输来的 ASCII码(可能还包括Escape字符序列)做出响应,这种设备我们称之为哑终端(dumb terminal)。哑终端相对于电传打字机速度要更快,从某种程度来讲也更灵活,但从速度的提高程度上来讲,并不足以引领用户界面的革新。真正的革新出现在20世纪70年代小型计算机中—它类似于第21章我们构建的假想计算机,配备了“视频显示存储器”,并作为微处理器地址空间的组成部分。

编码隐匿在计算机软硬件背后的语言

400

PDF 物理页索引 417

文件中的第 418 页 · 印刷页码:401

第一个预示着家用计算机将与它的孪生兄弟体积庞大、价格昂贵的大型机划分界限的标志性的事件是VisiCalc的使用。VisiCalc由丹·布莱克林(Dan Bricklin,生于1951年)和鲍勃·弗兰克斯顿(BobFrankston,生于1949年)设计并编程实现,而这套系统于1979年引入苹果Ⅱ型电脑(AppleⅡ)中。VisiCalc通过屏幕将一个二维电子数据表呈现给用户。在VisiCalc出现之前,数据表就是一张划分好了行、列的纸,主要用于一系列计算。VisiCalc用视频显示器将纸质材料取而代之,通过这种方式,用户可以在数据表中随处游走,在相应位置输入数据、公式,并在修改后对结果进行重新计算,为用户提供了更多的自由。

令我们惊讶与无奈的是,VisiCalc这款应用程序无法在大型机上运行。因为像VisiCalc这类程序需要以较快的速度不断更新屏幕,所以,它们直接将数据写入AppleⅡ视频显示器所配备的RAM中。该RAM是微处理器地址空间的一部分。大型时分计算机以及哑终端之间的接口速度过慢,以至于电子报表程序无法使用。

计算机对键盘的响应速度越快,对视频显示器的更新速度越快,则人机交互就越频繁。在IBMPC刚刚推出的10年里(即20世纪80年代),几乎搭配的所有软件都是直接将输出的数据写入视频显示存储器的。当时IBM建立了一套硬件标准,其他硬件制造商参照这些标准去生产,这样软件制造商就可以绕过操作系统直接操控硬件,统一化的硬件标准确保了程序的正确运行(同时也杜绝了不能运行的情况)。如果所有同构的PC都拥有异构的视频显示器硬件接口,这种做法无异于将软件厂商推到了火坑里,因为做软件的同时还要关注硬件设计细节是不现实的。

IBM早期PC配备的应用程序通常只有字符输出,很少有图形输出。使用文本输出大大加快了应用程序的运行速度。假设PC上配备一台第21章所描述的视频显示器,那么程序所要做的就是把字符相应的ASCⅡ码写入内存,然后屏幕上就会显示出该字符。但是如果使用的是图形视频显示设备,那么相应的程序需要将8个或更多的字节写入到内存中,这样做的目的就是画出字符的外观并以图形的方式显示。

在计算机的发展史上,从字符显示到图形显示是一次伟大的变革,计算机在这次变革中迈出了重要的一步。然而,相对于显示文本和数字所采用的软硬件,图形化计算机的软硬件发展十分缓慢。早在1945年,约翰·冯·诺伊曼(John vonNeumann)就预见了一种类似示波器的显示器,它的最大特点是可以显示图像化信息。但直到20世纪50年代早期,MIT(当时得到了IBM资助)建立了林肯实验室,实验室的主要任务就是帮助美国空军开发一种适用于防空系统的计算机,这次项目使计算机的图形化成为现实。该项目被称为半自动地面防空系统,简称 SAGE(Semi-Automatic Ground Environment),项目的内容包括构建一个显示图形的屏幕,以此来帮助操作员分析海量数据。

25 图形化革命

401

PDF 物理页索引 418

文件中的第 419 页 · 印刷页码:402

早期的视频显示器,比如SAGE中使用的这一种显示器,与我们今天所使用的PC配套显示器不尽相同。我们日常所用的PC配套的纯平显示器属于光栅(raster)显示器。它的原理就像电视机,每一幅图像背后都是一行行的光栅线,这些光栅是电子枪(electrongun)发出光束迅速来回移动覆盖整个屏幕而形成的。我们可以把屏幕想象成一个巨大的矩形阵列,阵列的每个元素都是一个点,这些点称为像素(pixels)。在计算机内部,有一块专门供视频显示器使用的内存区域,屏幕上的每一个像素点由1个或多个比特表示。这些二进制数值不仅决定了像素点的亮度,还决定了它的颜色。

举例来讲,当今大多数计算机显示器的水平分辨率至少为640个像素值,垂直分辨率至少为480个像素,像素总和即两数之乘积:307,200。如果为每个像素赋予1比特内存空间,这时每个像素点只能有两种颜色,通常设置为黑、自两种颜色,比如可以设置让0代表黑色,1代表白色。这种视频显示器需要占据307,200比特的内存,换算过来就是38,400字节。

由于要用到的颜色数目逐渐增加,为了表示这些颜色,每个像素所需要的比特越来越多,显示适配器需要配备的存储器容量也越来越大。比如我们想使像素点具备不同的灰度,那么可以提供一个字节的存储空间。在这种处理方式下,字节00h代表着黑色,FFh代表着白色,两者之间的值代表着不同的灰度。

CRT上的色彩空间由三个电子枪产生,每一个电子枪分别产生三原色中的一种,包括红色、绿色、蓝色(用放大镜来观察电视机或彩色计算机屏幕,你可以清楚地看到,每一幅图像都是利用许许多多不同的三原色组合显示出来的),红绿组合出黄色,红蓝组合出品红色,蓝绿组合是青色,三原色组合出白色。

在最简单的彩色显示适配器中,表示每个像素点需要3个比特。最直观的编码方式就是每一种原色对应编码中的1位。

编码—隐匿在计算机软硬件背后的语言

402

PDF 物理页索引 419

文件中的第 420 页 · 印刷页码:403

这种方案可能只适合简单的类似卡通画的图像。真实世界出现的几乎所有颜色都是由红、绿、蓝三原色的不同色阶(levels)组合而成的。如果为每个像素赋予2个字节的存储空间,这样一来,可以给每一个原色分配5位(1位保留)存储空间,这种方法可以表示出红、绿、蓝三种颜色且每种颜色具备32种不同的色阶,这样算下来总共有32,768种不同的颜色。这种模式通常称做高彩色(high color)或数干种颜色(thousands of colors)。

我们下面尝试一下用3个字节来表示一个像素,三原色中的每一种各占一个字节。这种编码模式使红、绿、蓝各自呈现出256种不同的色阶,这样算下来共有16,777,216种不同的颜色,这种方案通常叫做全彩色(full color)或百万种颜色(millions of colors)。如果视频显示器的分辨率为640×480,即水平640像素,垂直480像素,将像素点的数量乘以表示每个像素点需要的字节数可以得到,共需要921,600字节的存储容量,即将近1MB。

每个像素所赋予的比特数有时也称做色深(colordepth)或色彩分辨率(colorresolution)。颜色数与单个像素被赋予的比特数的关系如下:

$$
3 ) \textcircled { 1 } Z � s t 3 = 2 ^ { 2 }
$$

如果视频适配卡配备的存储器容量有限,那么它的最大色深或色彩分辨率自然而然也受到约束。假设有一个配备了1MB存储器的视频适配卡,在每个像素被赋予3个字节的情况下分辨率可以达到640×480。如果想把分辨率提高到800×600,存储器就不足以为每个像素赋予3个字节,必须缩减到用2个字节来表示一个像素。

虽然现在来看在显示器上使用光栅技术似乎是很自然的事情,但是在早期,这种做法并不可行,因为在当时看来,这种技术需要的存储器空间太大。在这种情况下SAGE视频显示器应运而生,它是一种矢量(vector)显示器,相比电视机,它更像一种示波器。

25 图形化革命

403