☰
《编码》读书笔记:从二进制到CPU,补足计算机底层认知的必修课
2026/9/29 4:16:15 网站建设 项目流程

在看到书名《编码:隐匿在计算机软硬件背后的语言》时,我第一反应是:这本书终于被更多人看到了。做开发这些年,我见过太多人从C语言、Python入门,却对计算机怎么从“通电/断电”变成能跑程序的这件事一无所知。而这本书,恰好把这条理解链补得严严实实。它不是一本工具书,不会教你写某一门语言的语法,但它像一张地图,把摩尔斯电码、继电器、逻辑门、汇编器、操作系统这些看似无关的东西串成一条清晰的线。读完之后你会意识到:所谓“编码”,不只是在电脑里存字符串,而是整个计算机世界运转的底层契约。

如果你是一个被指针搞到头大的C语言新手,或者一个想搞懂计算机组成原理但被教材劝退的学生,再或者一个写了好几年业务代码却总感觉“地基不牢”的开发,这本书都值得花一个周末啃完。我自己是工作到第三年才读它的,读完只有一个想法:早知道当年就该在学C语言之前先看这本书。

1. 为什么一本20多年前的书到今天仍然是“必修课”

先说一个反直觉的事实:这本书首版出版于1999年,作者Charles Petzold是美国老牌技术作家,写过Windows编程领域的经典教材。但今天去看它,内容一点都不过时。因为计算机的底层逻辑这几十年根本没有变过:依然是二进制、依然是逻辑门、依然是冯·诺依曼结构。变的只是工艺和规模,从继电器到真空管到晶体管再到芯片,本质没变。

很多初学者会有一种错觉:技术更新这么快,老书是不是该淘汰了?恰恰相反。越是底层、越是基础的知识,越稳定。比如CPU的指令集、内存寻址方式、中断机制,这些概念在几十年前的教科书里就有,今天的CPU只不过是把它们塞进了更小的面积、更高的频率。你不可能跳过二进制和逻辑门直接理解CPU怎么工作,就像你不可能跳过加减法直接学微积分。

这本书的另一个价值在于,它把“抽象”这件事讲透了。程序员每天都在跟各种抽象打交道:函数、类、接口、操作系统、虚拟机。但抽象不是凭空来的,每一层抽象都有自己的物理基础。书里面从最开始的“用灯泡传递信息”讲起,一步一步告诉你:为什么需要编码?编码如何被硬件实现?指令是怎么从人的语言变成机器能懂的信号?这个过程走完之后,你对“抽象”的理解会从“用着方便”变成“知道它为什么长这样”。

还有一点必须提:这本书的中文译名《编码:隐匿在计算机软硬件背后的语言》非常贴切,但它的英文原名是《Code: The Hidden Language of Computer Hardware and Software》。注意“Hidden”这个词。那些隐藏在日常开发背后的东西——字符集、总线、时钟信号、地址解码、汇编指令——才是计算机真正的骨架。你天天用IDE写代码,但这些工具背后的机制,大部分人都是一团迷雾。这本书就是来拆开迷雾的。

2. 从摩尔斯电码到二进制:编码的演化逻辑

作者很聪明,没有一上来就讲晶体管和CPU,而是从你最熟悉的东西切入:文字和密码。人类早就学会了用符号来代表信息,比如字母表、象形文字、摩尔斯电码。摩尔斯电码其实就是一个典型的编码系统:用点和划的组合表示字母和数字,通过长短信号传递。

这里有个关键点:编码最重要的不是“用什么符号”,而是“符号和含义的约定关系”。摩尔斯电码里,SOS被规定为“···— — —···”,这只是约定。换一套约定,SOS也可以变成别的。计算机编码的逻辑完全一样:二进制里的0和1本身没有意义,但当我们约定“01000001”代表大写字母A的时候,编码就产生了。

书中用了一个特别好的类比——手电筒。想象你用一个手电筒在黑暗中传递信息:开和关,只有两种状态。如果你只靠“开”和“关”两种状态,每次只能表达两种信息。但如果你把开关状态拼成序列,比如“开-开-关-开”,你就能表达更多信息。这就是二进制的雏形:用多个二进制位(bit)的组合来表示任意信息。

作者由此引出了“比特”和“字节”的概念:一个比特是0或1,八个比特组成一个字节,可以表示256种不同状态。为什么是256?因为2的8次方等于256。这解释了为什么基本字符集是128个ASCII字符(7位)或扩展后的256个(8位),也解释了为什么一个字节能存一个普通的英文字符。汉字因为在几千个甚至几万个,所以需要多个字节来编码,于是有了GB2312、GBK、UTF-8这类不同方案。

我在读这段的时候最大的收获是:编码不是“计算机发明的语法”,而是一种“人和机器之间约定的语言”。你写的每一个字符,敲的每一个回车,最终都要变成一串二进制数字。不同编码方案的差别,只是“哪串数字对应哪个字符”的映射表不同。理解了这一点,后面再看字符乱码、编码格式转换、HTTP请求里的charset,就再也不慌了。

3. 继电器、逻辑门与“会计算的机器”

书的中段是最高能的部分:从继电器讲到逻辑门,再讲到加法器、触发器,最后组成一个完整的CPU。这里的阅读体验就像在搭积木,每一块都扣得严丝合实。

作者选择了继电器作为起点,因为它是早期计算机的核心开关元件。继电器本质上是一个电磁开关:通电时吸合,断电时释放,于是可以控制电路的通断。这个“通”和“断”,正好对应二进制的1和0。用继电器做开关,再用多个开关组成电路,就可以实现逻辑运算。

这里要强调“逻辑门”这个概念。逻辑门是对“与、或、非”布尔运算的电路实现。比如一个“与门”有两个输入,当两个输入都是1时,输出才是1,否则输出0。用继电器可以拼出与门、或门、非门,然后用这些门拼出更复杂的电路。最神奇的是加法器:把两个二进制数加在一起,只需要组合一堆逻辑门就能实现。半加器处理一位加法,全加器还能处理进位,多个全加器串起来,就能实现多位二进制加法。

书里有一张经典的图:用继电器搭成的一个8位加法器。我第一次看的时候拍案叫绝——原来计算的本质就是逻辑运算。加法是逻辑,减法可以转换成补码加法,乘法是多次加法,除法是多次减法。CPU里那个看起来无所不能的运算器,底层全是逻辑门的组合。

再往下,作者讲了存储:如何让电路“记住”一个值。这就是触发器(Flip-Flop)的由来。通过把两个逻辑门的输出交叉反馈到输入,就能形成一个双稳态电路:正常情况下保持原来的状态不变,只有输入信号触发时才翻转。一组触发器可以存储一个比特,许多组触发器排在一起就成了寄存器。寄存器再集成起来,配上地址译码电路,就形成了内存的雏形。

读到这我意识到一件事:计算机的CPU、内存、总线,这些高大上的名词,其实都是逻辑游戏的物理具象化。你不需要理解半导体的量子力学才能明白CPU怎么工作,你只需要理解逻辑门、触发器和它们之间的连接方式。这正是这本书最厉害的地方:让没有任何硬件基础的人也能看得懂计算机的“骨架”。

4. 从汇编到C语言:软件层面对编码的延续

如果这本书只讲硬件,它充其量是本数字电路教材。但它真正的亮点,是从硬件跨到了软件:如何让机器执行复杂的指令,以及如何让人类用接近自然语言的方式编程。

这一步的关键是“指令”。加法器只能做加法,但我们希望计算机能做“读取内存、比较大小、跳转、输出”这种事情。于是工程师设计了一组指令,每个指令有一个操作码,告诉CPU做什么操作,再配上操作数,指定操作的对象。一串指令按顺序排列,就形成了一个程序。CPU通过一个不断累加的“程序计数器”来逐条读取指令并执行。这个模型,就是冯·诺依曼结构:存储程序、顺序执行。

早期程序员写程序就是直接写这些二进制指令,痛苦不堪。后来有人发明了汇编语言:用助记符(比如ADD、MOV、JMP)代替二进制操作码,用符号代表内存地址。汇编器负责把这些人类可读的文本转换成机器码。这就是“软件”的起源——汇编器本身就是第一个真正意义上的系统软件。

再往后,出现了更高级的语言。C语言就是其中最典型的代表。为什么这本书和C语言的关系这么紧密?因为C语言的设计哲学,就是用一种更接近人类思路的方式,来表达“机器能做的事”。C语言里的指针,直接对应内存地址;数组,对应一片连续的内存;函数调用,对应栈帧的压入和弹出。如果你理解了书里讲的内存模型和指令执行过程,再回头看C语言指针,你会豁然开朗:指针就是一个存储了地址的变量,没有玄学。

我自己的经历很典型。本科上C语言课,对指针一知半解,考试背题勉强通过。后来读了这本书,回头写了几个操作链表的例子,突然就通了。因为我知道一块内存地址长什么样,知道“存地址的变量”和“地址指向的变量”是两码事。这种理解不是来自任何编程技巧,而是来自对底层编码的认知。

这本书也花了篇幅解释“机器码→汇编→高级语言”这条演化路径的原因:人脑不擅长处理0101,但机器擅长。于是每一层抽象都是为了让人和机器更好地协作。底层并没有消失,只是被包裹起来了。你现在用Python写个print("hello"),背后依次经过解释器、操作系统、CPU指令集,最终仍是一堆逻辑门在翻飞。这个链条,在这本书里被完整地呈现了出来。

5. 读完这本书后我重新理解的几个“编码”细节

这本书带给我的不只是知识,更是一套用来解释日常开发问题的思维框架。有几个细节我是在实际工作中遇到问题后,回头看书才真正想明白的。举几个例子。

乱码问题。以前遇到网页乱码,我的第一反应是“字符集没设置好”。但读了这本书,我理解到:乱码的本质,是同一个字节序列在不同的“编码约定”下被解释成了不同的字符。比如“编码”两个字的GBK编码是某几个字节,如果按照UTF-8去解码,就得不到正确的字符。这不是数据错了,而是解释错了。这就像同一串莫尔斯电码,用不同的码本去翻译,得到的结果自然不同。真正理解这个,排查乱码时就不会瞎试编码格式了。

struct的内存对齐。在C语言里,struct的成员之间可能有填充字节,因为CPU访问对齐的内存地址更高效。如果不理解底层,你会觉得这是什么编译器怪癖。但当你知道了内存是按字节编址、CPU一次取多个字节、总线宽度决定一次能取多少位,你就能理解内存对齐是为了让硬件简化设计、提高效率。这属于典型的“软硬件交界处的编码问题”。

网络字节序。不同的CPU在内存中存放多字节数据时,字节顺序不同(大端和小端)。网络传输时为了统一,规定了网络字节序。这个问题的本质,同样是“约定”:同一串字节,按什么顺序解释。如果两台机器约定不一致,数据就乱套了。理解了这一点,写通信代码时自然会注意htons、ntohl这种转换。

缓冲区和溢出。书里讲到存储器和地址的概念后,我再看C语言的缓冲区溢出漏洞就特别明白了:一个变量分配了一段固定大小的内存,如果写入的数据超过了这个大小,就会覆盖相邻内存里的内容。攻击者可以利用这一点改写返回地址,让程序执行恶意代码。这虽然是安全知识,但根子上依旧是“编码和内存模型”的问题。不懂底层,永远只能在表面补洞。

字符串编码的复杂性。ASCII、UTF-8、UTF-16,这些名词如今已经成为面试必问。我建议你去读一下书中关于字符编码的那几章,再看一篇文章叫“每个程序员都应该了解的字符编码知识”,基本就能把这块彻底拿下了。核心就一句话:字符集是“字符和编号的对应表”,编码方案是“编号如何在字节里存放”,两者不是一回事。UTF-8是一种变长编码,为了兼容ASCII,同时减少存储空间;UTF-16则是固定两个字节起跳,对于绝大多数常用汉字也能两个字节存下。这些选择背后都是工程权衡。

6. 如何把这本书读出最大价值:阅读顺序和配套资源

这本书不适合像看小说一样从头扫到尾。正确的姿势是“边读边模拟”,最好手边放几张纸和一支笔。我自己是这么读的:

第一遍:快速浏览全书,重点看每章的图和代码示例,知道作者在讲什么,不要纠结细节。这一遍的目的是建立整体框架。第二遍:针对自己最模糊的部分精读,比如“内存怎么寻址”“CPU怎么执行指令”,一边读一边画图,把一个字节从内存到CPU再到寄存器的路径画出来。第三遍:带着问题去重读,比如“为什么负数要用补码表示?”“为什么指针可以有不同类型?”这些问题很多都是书里内容在编程场景中的应用。

如果你已经有点基础,可以直接跳着读:第一章到第四章讲编码基础,可以快速过;第五章到第十章是继电器、逻辑门、加法器,强烈建议细读;从第十二章开始,会进入存储、指令、汇编、操作系统等话题,逐步接近现代计算机;到了后面的章节,你会看到怎么从部件组装出整台计算机。整本书读完大概需要20到30个小时,分一周慢慢读就好。

另外我强烈建议搭配以下资源一起服用:

  • C语言教程:翁恺老师的C语言课程,网上有公开版。边读《编码》边学C,你会看到C语言里的每一个特性在硬件层面的根基。
  • 计算机组成原理教材:如果想在《编码》基础上再深入,可以看“计算机组成与设计”或者国内的“计算机组成原理”教材。注意,先读《编码》再读教材,你会有一种“原来如此”的顺畅感。
  • 在线电路模拟器:有些网站提供了交互式逻辑门模拟,可以自己拖线搭一个加法器出来。亲手把逻辑门连成电路,比看书里的静态图理解深得多。
  • 调试工具:如果你写C语言,用gdb看变量地址和执行流程,把内存视图显示出来,去观察指针、栈帧、寄存器。这会让你把书上的抽象概念落到真实运行的程序上。

不要贪多,一次一个主题。很多读者反馈说这本书“像小说一样停不下来”,但真正常读常新的,是你把它当成一本“计算机世界观”的启蒙书,而不是技术手册。

7. 那些读完之后我依然记得的“高光时刻”

到这里我想说几个具体片段,这些都是这本书留给我的记忆点,也是它区别于普通教材的地方。

第一个高光时刻是“巧妙的二进制减法”。作者讲解补码的时候,没有直接丢公式,而是从“拨动十进制计时器的轮盘”这个场景引入:倒计时怎么表示?借位怎么处理?然后引申到二进制的原码、反码、补码。读完你会觉得补码不是人为规定的怪规则,而是为了让减法统一成加法、让电路设计更简洁的自然结论。理解了这一层,以后看到某个数取反加一,你就知道它在硬件层面意味着什么。

第二个高光时刻是“从灯泡编码到计算机的演进步骤”。前几章作者用一个手电筒和一个接收者,展示了信息的两种状态如何组合成复杂的消息。然后一步步扩展到“如果我们有很多开关”“如果开关可以自动控制”“如果我们可以把结果保存下来”,最终引出了计算机的雏形。这种从最简单模型开始不断迭代的叙事方式,让完全零基础的人也能跟上节奏。

第三个高光时刻是“CPU的构成”。最后几章里,作者把运算器、控制器、寄存器堆、总线搭在一起,形成了一台真正可以执行程序的8位计算机。他甚至给出了简单指令集,你可以亲手模拟每条指令的执行流程。当你看到一条“LDA #5”的指令,从取指、译码到执行,一步步改变状态的时候,你会有一种“我看穿了计算机本质”的通透感。这种成就感,是任何视频教程都给不了的。

说实话,这本书并不算新手友好的“快速入门书”,它需要你投入耐心。但它给予你的回报是长期的:当你以后再学新语言、新框架,你会知道它们不过是底层机器的另一种“编码”方式。你会习惯性地追问:这个特性在底层是如何实现的?这套机制背后是在解决什么问题?这种追问,正是高手和新手的本质区别。

8. 一个小建议:读完一定要动手“拆”一次

如果你问我,读完《编码》之后最值得做的事是什么,我的答案是:亲手拆解一台电脑,或者找一个模拟器,从CPU和内存的角度去运行一个最小的程序。

我在读完书后的周末,专门做了这么一件事:打开一台旧笔记本,把内存条拔下来,看金手指上的印刷电路和引脚排布,对照书里的“地址线”和“数据线”概念,瞬间理解了内存条为什么是那么多引脚。然后再装回去,开机,用一个小工具查看CPU的缓存信息,想想指令是怎么在缓存和内存之间流动的。这个过程,比读十篇博客都管用。

如果你没有硬件,也有更轻量的办法:用QEMU模拟一台无操作系统的机器,写一小段汇编代码,用调试器单步执行,看CPU寄存器和内存的变化。不需要多复杂,“让CPU把一个数从内存搬到寄存器再加一”就够了。当你在屏幕上看到某个寄存器的值因为你写的一条指令而改变时,你就真正和这本书产生了连接。

这些年我带过不少新人,发现一个普遍规律:基础扎实的人,遇到新问题不会慌,因为他们能往底层拆;基础薄弱的人,哪怕会用各种框架,一旦遇到诡异bug,就只能靠猜。而《编码》这本书,就是打地基最快的一条路。它不会让你马上能写更快的代码,但它会给你一种“眼见为实”的底气。

如果你手头正在学C语言,或者对计算机组成原理头疼不已,我建议你把这本书放在你的显示器旁边,每天读一章。慢没关系,不懂也没关系,先让那些概念在脑子里留下影子,等某天你调试一个指针错误,或者看到一个乱码页面的时候,那些文字会突然跳出来,让你笑出声:原来它就在讲这个。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询