---
schema_version: "library-reader-v1"
source_type: "original_book"
title: "编码 隐匿在计算机软硬件背后的语言"
author: null
edition: null
publisher: null
year: null
isbn: "9787121181184"
library_document_id: "38270854-596f-4a26-8183-db8c968c6020"
source_sha256: "249786274d83909f0bddc34d77f81ed8f0b14d1eac8843c772a37a3ecbfe2cfc"
pdf_physical_page_count: 438
pdf_physical_page_index_base: 0
range_start: 320
range_count: 10
html_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020?start=320&limit=10"
markdown_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=320&limit=10"
previous_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=310&limit=10"
next_url: "https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=330&limit=10"
---

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

> 页码规则：PDF_PHYSICAL_PAGE_INDEX 是从 0 开始的权威文件物理页索引；PRINTED_PAGE 是页面中识别出的印刷页码，可能为空，二者不得混用。

## PDF_PHYSICAL_PAGE_INDEX=320 | PRINTED_PAGE=304

争论两者之间哪一种方式更好是件有趣的事，但在这么做之前，先要知道big-endian这个术语出自乔纳森·斯威夫特(Jonathan Swift)的 Gulliver 's Travels，指的是刘普特(Lilliput)和布鲁夫思科(Belfuscu)之间关于在吃鸡蛋之前应该把鸡蛋的哪一头敲碎的争论。因此，这种争论可能是没有意义的（另一方面，坦白地说，在本书第17章设计的计算机所采用的方式我个人并不喜欢)。尽管不能确定那一种方式本质上是“对的”，这种差别确实造成了附加的兼容性问题，这种问题通常会在采用 little-endian和 big-endian系统的机器共享信息时出现。

这两种微处理器后来的发展如何呢？8080被应用在一些人所谓的第一台个人电脑（personal computer）上，更准确地说应该是用于第一台家用电脑（home computer）上。下图是 Altair 8800，它曾登上了1975年1月的 Popular Electronics 杂志的封面。

当你看到Altair8800时，前面板上的灯泡和开关会让你感到似曾相识。这个界面和第16章介绍64KB RAM阵列时的初始“控制面板”的界面是类似的。

在8080之后，Intel又推出了8085芯片，而具有更重大意义的是Z-80芯片的出现。Z-80是由Zilog公司制造的，该公司是英特尔公司的竞争对手，由英特尔的前雇员费德瑞克·菲戈金（FedericoFaggin）创立，费德瑞克·菲戈金曾在4004芯片的研制过程中做出重要贡献。Z-80和8080完全兼容，并且增加了许多非常有用的指令。1977年，Z-80曾被应用在 Radio Shack TRS-80 Model 1 上。

同样是在1977年，由斯蒂夫·乔布斯（Steven Jobs）和史蒂芬·沃兹内卡（StephenWozniak）创立的苹果计算机公司推出了新一代产品 AppleⅡI。AppleⅡ既没有使用 8080也没有使用6800，而是使用了基于MOS技术的更加便宜的6502芯片，它是6800的改进加强版本。

304

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

## PDF_PHYSICAL_PAGE_INDEX=321 | PRINTED_PAGE=305

1978年6月，英特尔公司推出了8086芯片，这是一个16位的微处理器，可以寻址1MB的地址空间。8086的操作码与8080不兼容，但它包含了乘法指令和除法指令。一年后，英特尔推出了8088芯片，其内部结构与8086完全相同，但在外部仍以字节为单位（即外部接口为8位）访问存储器，所以该芯片能使用为8080设计的较为流行的8位的外围芯片（8-bit support chips)。IBM 在 5150 个人计算机中使用了8088 芯片，这种计算机通常称为IBMPC，于1981年秋季推出。

IBM大举进军个人计算机（Personal Computer，有时也简称为PC）市场对业界产生了重大影响，许多公司都推出了与个人计算机兼容的机器（兼容的含义将在随后的几章里详细讨论）。多年以来，“IBM PC兼容”也暗示了“Intel inside”（即内部使用了Intel微处理器)，这里特指Intel x86系列微处理器。x86系列微处理器包括1982年发布的186芯片和286芯片，1985年发布的32位386芯片，1989年发布的486芯片。从1993年开始，英特尔公司推出Intel奔腾（IntelPentium）系列微处理器，而这个系列如今被广泛地应用于PC兼容机。虽然这些处理器的指令集都在不断扩展，但是它们仍然支持始于8086的所有早期处理器的操作码。

苹果公司的Macintosh于1984年首次发布，它采用摩托罗拉的68000微处理器，68000是16位微处理器，是6800的下一代产品。68000及其后续产品（通常称为68K系列）是已发布的处理器中最受欢迎的一类。

从1994年开始，Macintosh计算机开始使用PowerPC微处理器，该处理器是由摩托罗拉，IBM以及苹果公司联合开发的。PowerPC是采用 RISC（Reduced Instruction SetComputing，精简指令集计算机）微处理器体系结构来设计的，其目的是通过某些方面的简化来提高处理器的速度。在RISC计算机中，通常指令都是等长的（PowerPC中是32位)，只有加载和保存两种指令能访问存储器，并且尽量简化指令的操作。RISC处理器设置了大量的寄存器，这样就能避免频繁访问存储器以提其高运行速度。

PowerPC拥有完全不同的指令集，因此不能执行68K系列微处理器的代码。然而，目前 Macintosh 计算机使用的 PowerPC 微处理器可以仿真（emulate）68K 系列微处理器。运行在PowerPC上的仿真程序逐一检查68K程序的操作码，并执行相应的操作。它执行的速度没有PowerPC本身的代码那么快，但可以正常工作。

19 两种典型的微处理器

305

## PDF_PHYSICAL_PAGE_INDEX=322 | PRINTED_PAGE=306

根据摩尔定律（Moore'sLaw)，微处理器中的晶体管数量每18个月翻一倍，人们不禁要问：增加的这些大量的晶体管用来做什么呢？

一些晶体管用来适应处理器不断增加的数据宽度—从4位、8位、16位到32位；另一些新增的晶体管用来应对新的指令。例如，现在大部分微处理器都支持用于浮点数的指令（将在第23章详细介绍)；还有一些新增的指令用来执行重复计算，以便在计算机屏幕上呈现图片和电影。

现代处理器使用多种技术来提高其运行速度。其中一种就是流水线技术(pipelining)，即处理器在执行一条指令的同时读取下一条指令，尽管Jump指令在一定程度上会改变这种流程。现代处理器还包括一个Cache（高速缓冲存储器)，它是一个设置在处理器内部，访问速度非常快的RAM阵列，用来存放处理器最近要执行的指令。由于计算机程序经常执行一些小的指令循环，使用Cache可以避免反复加载这些指令。上面提到的这些提高运行速度的策略都需要在处理器内部增加更多的逻辑组件和晶体管。

正如前面所提到的，微处理器只是整个计算机系统的一部分（尽管是最重要的一部分）。我们会在第21章构造这样一个系统，但首先要学习如何处理存储器中的数据，包括操作码和数字，我们要对这些数据进行编码。让我们从心态上回归到小学一年级，像孩子们学习读写一样学习如何编码吧。

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

306

## PDF_PHYSICAL_PAGE_INDEX=323 | PRINTED_PAGE=NOT_DETECTED

ASCII码和 字符转换

数字计算机中的存储器唯一可以存储的是比特，因此如果要想在计算机上处理信息，就必须把它们按位存储。通过先前的学习，我们已经掌握了如何用比特来表示数字和机器码。现在我们面临的一大挑战就是如何用它来存储文本。毕竟，人类所积累的大部分信息，都是以各种文本形式保存的。文本信息聚集最多的地方之一就是图书馆，数不清的书、杂志和报纸所提供的都是文本信息。当然，我们现在已经使用计算机来存放图像和影音信息了，不过为了易于理解，我们还是先从如何使用计算机存放文本开始讲解。

为了将文本表示为数字形式，我们需要构建一种系统来为每一个字母赋予一个唯一的编码。数字和标点符号也算做文本的一种形式，所以它们也必须拥有自己的编码。简而言之，所有由符号所表示的字母和数字（Alphanumeric）都需要编码。具有这种功能的系统被称为字符编码集(Coded Character Set)，系统内的每个独立编码称为字符编码(Character Codes)。

许多疑问也随之而来，而要解决的第一个问题是：构成这些编码究竟需要多少比特？

## PDF_PHYSICAL_PAGE_INDEX=324 | PRINTED_PAGE=308

要想回答这个问题就需要我们从长计议了。

当考虑用比特来表示文本的时候，切忌好高骛远。我们经常会看到书页上，或报刊和杂志的栏目上所有的内容被整齐地组织在一起。所有的段落都划分为宽度相等的文本行，但我们要注意，这种排版的形式永远只是文本之外的事物。当曾在某个杂志上细细品味过的一个故事，几年后与我们在另外一本书中重逢时，我们回忆起的往往是故事本身而不是文本的排版，没有人会因为行与行间距的不同而把它们当成两个故事。

我极力想阐述一个重要的观点，那就是文本与其印刷在纸上时采用的二维排版格式是两码事。充分发挥想象力，将文本看成是一维的由字母、数字和标点符号组成的数据流吧。当然，有时为了标明一句话的开始和结尾，还需要一些额外的编码。

还是先前所描述的例子，曾在某个杂志上细细品味过的一个故事，几年后出现在另外一本书中，但是文章的字体发生了变化，这算是一个问题吗？当年的杂志上是这样印刷的：

$$
\mathsf { C a l l \ m e \ l s h m a e l . }
$$

而现在书中的写法变成了下面这样：

Call me Ishmael.

这些区别是我们所在意的吗？答案往往是否定的。字体改变了文本的表现形式，但故事本身的内容并没有因此而改变。字体是可以变来变去的。但这并无大碍。

还有一种简化问题的方法：我们可以总是使用毫无修饰的文本。没有斜体、粗体、下画线、颜色、空心体、上标、下标以及音标，同样的，这里没有元音字母标识等符号，只有赤条条的拉丁字母，这些字母组成了英语中99%的文本。

在先前对莫尔斯码和布莱叶盲文的学习中，我们了解了如何将字母表中的字符以二进制的形式表现出来。这些系统在适合的场合很好用，但要想用到计算机中却是难上加难。就拿莫尔斯码来说，它是变量自适应长度（Variable-Width）编码：常用字符的编码较短，而不常用字符的编码较长。这样的编码非常适合电报系统，但并不适用于计算机。另外，莫尔斯码并不区分字母的大小写。

布莱叶盲文编码使用固定宽度，非常适合计算机使用。每一个字符对应着6比特的编码，并且用到了转义（Escape）码对大小写进行了区分。转义码用来表明下一个字符为大写。这也就是说，每个大写字母都需要两组编码来表示。布莱叶盲文中用移位（Shift)码表示数字：移位码后紧跟的编码都被看做数字，直到遇到下一个移位码，此时系统又将后面的内容当做字母。

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

308

## PDF_PHYSICAL_PAGE_INDEX=325 | PRINTED_PAGE=309

我们的目标是开发一个字符编码集，使用这个编码集，系统可以将如下的句子转换成为一系列的编码：

I have 27 sisters.

每一个字符的编码都会占据一定的比特。有的编码用来表示字母，有的用来表示标点符号，还有一些用来表示数字。甚至于单词间的空格也需要单独的编码。上面的句子中共18个字符(包括字间空格)，对这样一个句子进行编码后得到的连续字符通常被称为文本字符串（string）。

我们需要对字符串中的数字进行编码，例如上面的句子中的27。或许大家会感到疑惑，因为之前我们都是用比特来表示数字的。最简单的，也是最容易想到的做法就是使用二进制数10和111作为2和7的编码。但是这里却不适用。在这个句子中，可以像处理其他的字符一样来处理2和7。它们的编码可以和本身表示的含义无关。

1874年由法国电报服务公司（French Telegraph Service）职员埃米尔·波多（EmileBaudot）发明了可以打印的电报机，划时代的波多电传码也应运而生。即使在今天来看，这种编码十分“经济划算”，每一个文本字符都采用5位编码。这种编码1877年被法国电报服务公司采纳，后来经唐纳德·默里（DonaldMurray）修改，最终在1931年被当年的 CCITT 组织(Comité Consultatif International Télégraphique et Téléphonique)，即现在的国际电信联盟(ITU)定为标准。该编码的正式名称是国际电报字母表第二号(IntermationalTelegraph Alphabet No.2）或ITA- 2，在美国常常被称为波多印字电报制（Baudot)，不过更准确地说，叫做默里（Murray）编码。

随着 20 世纪的到来，Baudot 被广泛应用于电传打字机（teletypewriters)。Baudot 电传打字机配备了一个输入键盘，这款键盘有些像打字机，但只有30个键和一个空格键。电传打字机键盘上的每一个键实质上都起到了转换器的作用，它负责产生二进制编码并且通过输出电缆逐位传输出去。电传打字机也具备打印功能，通过输入电缆读取编码，

20 ASCII 码和字符转换

309

## PDF_PHYSICAL_PAGE_INDEX=326 | PRINTED_PAGE=310

触发电磁铁，从而将字符打印在纸上。

由于Baudot对每个字符采用5位编码，整个系统由32个编码所组成，这些编码的十六进制取值范围从00h到1Fh。下表给出了32个不同编码的十六进制形式及其所对应的字母表中的字符。

编码00h被保留了下来，没有指派给任何值。剩下的31个编码中，字母表中的字符占了26个，其余5个用来调整格式，如上表中的楷体排版的语句所示。

编码04h用来表示空格，通常用于分隔单词。编码02h和08h表示的是回车和换行。这些都是电传打字机中的专用术语。当使用电传打字机上打字，一旦到了一行的末尾时，我们通常会按下一个操作杆或按钮。这个操作其实包括两个动作：第一个动作是，使打印机的滑架回到起始位置，这样打印下一行时可以从纸的最左边开始，这就是回车。第二个动作是，将打印机的滑架移至正在使用中的位置的下一行，这就是换行。在Baudot编码系统中，这两个编码由专门的按键产生。Baudot电传打字机在打印的时候会响应这两个编码以完成相应的操作。

Baudot系统里怎么没有数字和标点符号呢？其实这是因为编码1Bh中暗藏玄机，它的实际作用是数字转义（Figure Shift)。数字转义编码后的所有的编码都会被解释为数字或标点符号，直到遇到字符转义编码（1Fh)，一切就又被解释为字符。下表展示了十六进制编码以及所对应的数字和标点符号。

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

310

## PDF_PHYSICAL_PAGE_INDEX=327 | PRINTED_PAGE=311

其实在ITU规范化的编码方案中，05h、0Bh和16h是留做他用的，官方说法为“国内使用”。表中列出的是这几个编码在美国使用时的含义。某些欧洲国家将这些编码代表重音符号。响铃编码令电传打字机发出清脆的铃声。“WhoAreYou”编码用来让打字员激活身份识别机制。

像莫尔斯码一样，这种5位的编码并没有提供区分大、小写的方法。下面这个句子：

$$
I S P E N T S 2 5 T O D A Y .
$$

表示成编码的十六进制数据流就是：

$$
\mathrm { O C ~ O 4 ~ 1 4 ~ O D ~ 1 0 ~ O 6 ~ O 1 ~ O 4 ~ 1 8 ~ 1 6 ~ 1 9 ~ 0 1 ~ 1 F ~ 0 4 ~ O 1 ~ O 3 ~ 1 2 ~ 1 8 ~ 1 5 ~ 1 8 ~ O 7 ~ 0 2 ~ 0 8 ~ }
$$

请注意三个转义码的使用：1Bh出现在数字之前，1Fh出现在数字之后，而数字结束之后又出现了1Bh。这一行编码以回车、换行符结尾。

问题出来了，如果把相同的数据流再一次输入到电传打印机，情况就大不一样了，

20 ASCII 码和字符转换

311

## PDF_PHYSICAL_PAGE_INDEX=328 | PRINTED_PAGE=312

如下所示：

I SPENNT \$25 TODAY.

8'03,5 \$25 TODAY.

怎么会这样？这是由于在接收到第二行编码之前打印机接收到的最后一个转义码是数字转义码，所以当遇见第二行开头几个编码时，打印机将它们解释成数字。

这种问题产生的根源就是采用了转义码，这的确很让人头痛。尽管Baudot电传码是很简洁实用的编码，但是，我们更加希望采用能唯一表示字符、数字及标点符号的编码方案，如果还能对大、小写进行区分那就更好不过了。

如果想知道比Baudot更好用的编码系统中一个编码需要多少比特，我们需要做几个小加法：所有的大小写字母加起来共需52个编码，0\~9数字需要10个编码，加起来共有62个，如果算上一些标点符号，数量超过了64个，也就是说，一个编码至少需要6比特。但无论如何字符数应该不超过128个，而且应该远远不够128个，也就是说编码长度不会超过8位。

所以，答案就是7。在采用7位编码时，不需要转义字符，而且可以区分字母的大小写。

这些字符编码是什么样子的呢？其实我们可以随意编码。如果我们要去打造一台自已的计算机，计算机硬件的每一个部分都要亲自制作，计算机内部的程序也要亲手编写，而且不打算把这台计算机与其他的进行连接，那么就完全可以构造自己的编码系统。其实也很简单，就是给每一个字符指派一个唯一的编码。

但是这种自己制造计算机，并且独立使用的情况实在是太少了，所以所有人都遵循并使用统一化的编码，计算机的存在才有意义。这样一来，使用不同方法制造出的计算机之间就可以互相兼容，甚至可以互相交流文本信息。

这样一来，随意的编码就显得不太合适了。当我们使用计算机来处理文本时，如果字母表中字母的编码是按顺序来的，就会给我们的工作带来很多便利，显而易见的优点就是，字母的排序和分类将变得简单易行。

幸运的是，这种标准已经存在并且被广泛使用，它被称为美国信息交换标准码(American Standard Code for Information Interchange)，简称为 ASCII 码，发音很像ASS-key。从1967年正式公布至今，它一直是计算机产业中最重要的标准。不过还有一个大的例外（后面会讲到），无论何时，当你在计算机上处理文本时，总会在不经意间使用到 ASCII 码。

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

312

## PDF_PHYSICAL_PAGE_INDEX=329 | PRINTED_PAGE=313

ASCI1码是7位编码，它的二进制取值范围为0000000\~1111111，对应于十六进制就是00h\~7Fh。现在我们一起来讨论下ASCI码，但我不建议从开始学起，因为相对于后面的编码，前32个编码理解起来还有一点难度。所以我们从第2组32个编码开始学习，它包括标点符号和10个数字。下表列出了这32个字符及相应的十六进制编码。

接下来的32个编码是大写字母和一些附加的标点符号的编码。除了@符号和下画线之外，其余的符号很难在打字机上找到。它们真正出现的地方是标准计算机键盘，下表列出了这些字符及相应的十六进制编码。

20 ASCII 码和字符转换

313

下一段：[继续读取](https://workshop.closeclaw.top/api/ai/read/38270854-596f-4a26-8183-db8c968c6020.md?start=330&limit=10)
