从一只小白鼠,到整个计算机世界
—— 一个下午的“串起来”
<div align="center">
<h3>📖 正文 · 思维脉络 · 课后随想 · 番外彩蛋 🎉</h3>
</div>
零、写在前面
今天下午,我从一个问题开始:
有1000瓶水,1瓶有毒,最少需要几只小白鼠,一次测出来?
答案是10只。因为10只老鼠,每只“死”或“活”,能产生2^10=1024种不同的结果,足够给1000瓶水每瓶一个唯一的“身份证”。
这个“身份证”,就是编码——用0和1代表东西的规则。
然后我一路往下问:编码怎么用?串行和并行有什么区别?校验位是干什么的?0/1和硬件是什么关系?软件是什么?操作系统在中间干什么?编译器是什么?API、DLL、虚拟机又是怎么回事?
最后,我把所有东西串在了一起。
这篇文章,就是那条串起来的线。
一、编码:用0/1代表世界
编码 = 用0/1代表东西的规则。
为什么用0/1?
因为硬件只有两种状态:通/断、高电压/低电压。
所以任何要让硬件做的事、存的东西,都必须先翻译成0/1。
小白鼠问题的核心,就是编码:
· 第1瓶水:0000000001
· 第2瓶水:0000000010
· 第3瓶水:0000000011
· ……
· 第1000瓶水:1111101000
规则:第1只老鼠喝所有第1位是1的水,第2只喝所有第2位是1的水……
结果:死=1,活=0,拼起来就是毒水的编号。
这不是“唯一”的规则,是我定的规则。
只要每瓶水的编码不重复,就行。
老师说,计算机思维就是用0和1去定义规则——0和1可以代表死/活、开/关、是/否,然后通过构建这些规则,来搭建你想要的世界。今天课上听的编码部分,说白了就是这个意思。
二、串行 vs 并行:两种用编码的方式
并行:n只老鼠,一次测完。
结果有2^n种,每瓶水对应一种。
空间换时间:老鼠多,测一次就知道答案。
串行:1只老鼠,测n次。
一次测一瓶,死在第n次就是第n瓶有毒。
时间换空间:老鼠少,但要多测几次。
小白鼠问题里,因为老鼠喝了毒水24小时后才死,所以只能用并行——一次测完,否则老鼠死了就没法测下一次。
但现实里还有别的考虑。比如硬盘和内存之间传输数据,为什么现在都用串行(SATA)而不是并行?因为并行线路多了会互相干扰,频率上不去。所以串行虽然在“时间”上慢,但能跑更高的频率,反而更快。这也是“时间换空间”的另一种体现——用更少的线,换更高的稳定性。
🎯 小插曲:后来我和AI聊天时,AI差点把串行说错——它说20瓶水用1只老鼠串行测需要“十几次”,我说“那不叫一瓶一瓶测吗?一瓶一瓶测就能完全确定哪一瓶有毒”。AI一开始还想辩解,最后发现自己想复杂了,承认错误。这个乌龙故事,放在文末番外里了。
三、校验位:多出来的菜单有什么用
2只老鼠,最多能测4瓶水。
如果我只测3瓶,就多出1张菜单没用(比如11)。
这张多出来的菜单,可以用来干别的事——比如检查有没有出错。
这就是校验位。
传数据的时候,我在数据后面加几位“校验位”,
这些校验位是按某种规则算出来的(比如让所有1的个数是偶数)。
接收方收到后,用同样的规则算一遍,如果对不上,就知道传错了。
· 1位校验位(1只老鼠) → 只能知道有没有错
· 多位校验位(多只老鼠) → 能知道哪一位错了(海明码)
校验位用在哪?
硬盘存文件、网络传网页、二维码、身份证、服务器内存……所有怕出错的地方,都在用。
四、硬件:谁认得这些0/1
0/1本身只是一串数字。
要让它们有意义,得有东西认得它们。
这个“认得它们”的东西,就是硬件。
硬件是什么?
· CPU:读0/1,按0/1的指令做事(加法、跳转、存数据)
· 内存:存0/1,CPU说“把地址1000的0/1给我”,它就给
· 硬盘:存0/1,断电也不丢
· GPIO引脚:软件说“输出1”,引脚就变高电压;说“输出0”,就变低电压
硬件的本质:用物理状态表示0/1,并按0/1的指令行动。
关于二极管
二极管是硬件世界里最基础的“开关”。
· 通电 = 1
· 不通电 = 0
几十亿个这样的开关组合在一起,就构成了CPU里的电路——有的负责加法,有的负责比较,有的负责存数据。
CPU“知道”哪串01是加法,不是因为它有意识,是因为工程师在设计时就把“加法指令”对应的电信号,物理地接通了加法器的电路。就像豆浆机“知道”按豆浆键就转刀片——不是学会了,是电路连死了。
CPU为什么“知道”机器码
CPU不是被“教会”懂机器码的。
它是在工厂里,被物理设计成这样的。
工程师画电路图的时候,就决定了:
· 如果某条电路收到10110000,就接通另一条电路,把某个值存进去
· 如果收到10000011,就接通加法器,把两个数加起来
这些电路是物理存在的,不是软件,不是程序。
所以CPU“知道”机器码,就像水“知道”往低处流——不是学的,是物理规律决定的。
用小白鼠的逻辑:你定规则“第1位是1就让鼠1喝”。老鼠不是“懂了”这个规则,是你把鼠1的笼子和第1位的信号线连死了。第1位来1,电信号过去,鼠1的食槽打开,它就喝。老鼠不是“知道”规则,是被物理连接决定了行为。
CPU也一样。它不知道,它只是被设计成:收到某些01,就做某些事。
ESP32与舵机
我玩ESP32开发板时,写myservo.write(90),最终就是让GPIO输出一串0/1,舵机收到这串0/1,转成机械转动。
ESP32怎么读懂上传的01?
ESP32里有一个CPU(Tensilica Xtensa),它专门读Flash里的01,一条一条执行。我上传的01就是它的机器码,它认得。这就像电脑的CPU认得.exe文件里的01一样——每个硬件都有自己的“母语”。
五、操作系统:硬件的管理员
硬件有了,0/1有了,谁来决定这些0/1什么时候跑、怎么跑?
操作系统。
你双击一个.exe文件:
1. 操作系统把这个文件从硬盘读到内存
2. 操作系统告诉CPU:“从这里开始执行”
3. CPU一条一条读内存里的01,执行
4. 如果程序要调API(比如读写文件、画窗口),操作系统帮忙
操作系统是管理员:
· 分配CPU时间(哪个程序先用)
· 分配内存(哪个程序用哪块)
· 管理文件、网络、设备
· 保护(不让一个程序破坏另一个)
操作系统本身也是机器码的01,直接跑在硬件上。
操作系统和CPU的关系
CPU是干活的人,操作系统是工头。
CPU只管一件事:读01,执行01。它不关心这些01是从哪来的、是谁的、下一个是谁的。
操作系统负责告诉CPU:“现在执行程序A的01,5毫秒后执行程序B的01,如果程序A想读文件,我来帮它调硬盘驱动。”
没有操作系统,CPU也能跑——跑你写的一个无限循环。但你想同时跑多个程序、想读写文件、想用网络,就得有人管这些事。那个人就是操作系统。
所以操作系统和CPU的关系是:
· CPU:硬件,执行01
· 操作系统:软件(也是01),告诉CPU执行哪些01、什么时候执行
六、编译器:把一种01翻译成另一种01
我写的C++代码,是给人看的:
```cpp
int a = 5;
int b = 3;
int c = a + b;
```

在电脑里,它也是01——ASCII编码的01。
int a = 5;在硬盘里存的是:
```
01101001 01101110 01110100 00100000 01100001 00100000 00111101 00100000 00110101 00111011
```
这串01,只有编译器认得。
编译器读它,知道“哦,这是一段C++代码”。
编译器做的事:
1. 读我的代码(ASCII的01)
2. 分析语法:int a = 5;是什么意思
3. 生成对应的机器码:10110000 00000101
输入是一种01,输出是另一种01。
编译器本身是什么
编译器也是一个软件。
它也是01,但它是另一种01——机器码。
我安装编译器的时候,装的就是一堆机器码的01。
我双击编译器图标:
1. 操作系统把这堆01从硬盘读到内存
2. CPU一条一条执行这些01
3. 这些01做的事:读我的代码(ASCII的01),输出新的01(机器码)
编译器 = 用01处理01的东西。
它读的01是我的代码,它写的01是机器码。
它自己也是01。
编译器、操作系统、CPU的关系
这三者的关系,像一条流水线:
· 我写的代码(ASCII的01)→ 交给编译器
· 编译器(机器码的01,由CPU执行)→ 读我的代码,生成.exe文件(机器码的01)
· 操作系统(机器码的01,由CPU执行)→ 把.exe读到内存,告诉CPU执行
· CPU(硬件)→ 执行这些01
编译器依赖操作系统:编译器运行时,需要操作系统把它从硬盘读到内存、分配CPU时间。
操作系统依赖CPU:操作系统的01,需要CPU来执行。
CPU依赖编译器:没有编译器,我的代码永远是ASCII,CPU看不懂。
七、软件:01的两种形态
软件也是01。
但软件有两种不同的“形态”。
形态一:我写的代码
我写的代码,在硬盘里是ASCII编码的01。
这串01,只有编译器认得。CPU不认得。
形态二:别人写好的软件
编译器、操作系统、浏览器、游戏——这些都是别人写好的软件。
它们已经是机器码的01,CPU直接认得、直接执行。
所以“软件生成0/1”这个说法,只有编译器这种软件才成立。
大多数软件不生成0/1,它们本身就是0/1,在执行。
❓ 一个小问题(AI后来考我的):
问:我写的int a = 5;在硬盘里存着的时候,是机器码的01,还是ASCII的01?
答:是ASCII的01。因为还没编译,还是源代码。编译之后生成的.exe才是机器码的01。
(这个问题我一开始答错了,但错完就记住了。)
八、API和DLL:别人给我搭好的桥
我写SolidWorks插件的时候,调了FeatureExtrusion2这个函数。
这个函数是SolidWorks提供的API(Application Programming Interface)。
API是什么?
· 别人把底层复杂的事做好了,封装成一个函数
· 我直接调这个函数,不用管它里面怎么实现
· 它自己会调操作系统,操作系统会调驱动,驱动会调硬件
我调的FeatureExtrusion2,最终会变成一串01,让SolidWorks画出一个拉伸特征。
DLL是什么
DLL(Dynamic Link Library)就是这些API的机器码形式——别人写好的功能包,编译成01,存在文件里。
我的程序运行时,直接调它,不用自己写。
如果我没有API,没有DLL,我想知道一个程序怎么工作的,就得逆向工程——把01翻译回人能看懂的代码。
但大多数时候,我不需要逆向。
别人把接口给我了,我直接调就行。
❓ AI问:API本身是ASCII的01,还是机器码的01?存在哪个文件里?
答:API的实现是机器码的01,存在DLL文件里。.h文件里只是它的“说明书”(函数声明),是ASCII的01,给人看的。
九、虚拟机:在软件里假装硬件
我之前用虚拟机装Linux,是在干什么?
我在Windows上装一个软件(VMware),这个软件假装自己是硬件:
· 它有假的CPU、假的内存、假的硬盘
· 我在里面装Linux,Linux信了,以为自己真的在一台电脑上跑
我在Linux里敲命令,Linux生成机器码的01,发给这个“假硬件”。
假硬件把这些01翻译成Windows能懂的01,Windows再让真硬件执行。
虚拟机 = 在软件里假装硬件
让为A硬件写的系统,跑在B硬件上。
这就是为什么我可以在Windows里用Linux。
❓ AI问:在虚拟机里敲ls,生成的01是直接发给真硬件,还是先发给谁?
答:先发给虚拟硬件(VMware假装的CPU)。虚拟硬件把这些01翻译成Windows能懂的01(系统调用),Windows再让真硬件执行。整个过程像嵌套了好几层翻译官。
十、把所有东西串起来

我现在可以站在高处,往下看:
最底层:硬件
CPU、内存、硬盘、GPIO
只认得机器码的01,只执行机器码的01
往上一层:操作系统
本身是机器码的01
管理硬件资源,调度程序执行,提供基础服务
再往上一层:编译器
本身是机器码的01
把我写的代码(ASCII的01)翻译成机器码的01
再往上一层:API / DLL
别人写好的功能包,是机器码的01
封装底层细节,让我直接调用
最上层:我写的代码
是ASCII编码的01
调API,被编译器翻译成机器码的01
交给操作系统执行,最终让硬件动起来
旁边一层:虚拟机
在软件里假装硬件
让为A写的系统跑在B上
贯穿始终的:01
编码 = 用01代表东西
校验位 = 在01里多加几位,防出错
渲染 = 把01转成人能看的图像
防火墙 = 检查进来的01,判断权限
十一、为什么现在做软件门槛低了
因为每一层都有人帮我封装好了。
以前:自己写驱动,自己管内存,自己处理网络,自己画界面
现在:操作系统帮我管,库(DLL)帮我实现,框架帮我搭结构,API让我直接调用
我只需要在最上面那层写几行代码。
门槛降低,不是因为事情变简单了,
是因为有人把复杂的事替我做了,藏起来了。
我站在巨人的肩膀上,不用自己再长一遍那么高。
十二、最后说几句
说实话,今天上《计算思维》课的时候,我听老师讲那些概念,全程云里雾里的,就觉得有点无聊。课后跟AI聊了一下午,才把这事给捋顺了。
其实大学里很多人都有这种感觉——课听着听着就飘了。不是老师讲得不好,而是人太多,每个人基础不一样,没办法因材施教。老师课上说了句话挺对:最好你自己之前做过一些项目,或者对这些东西有点概念,听课才会更有用。不然,光听“编码”“抽象”“接口”这些词,确实容易睡着。
我今天从一只小白鼠开始,一路问到:
编码、串行并行、校验位、硬件、软件、操作系统、编译器、C++和01的关系、API、DLL、虚拟机
我把这些东西串在了一起。
我不是背会了一堆名词,
我是看懂了一张地图。
以后遇到新东西,我可以问:
这是哪一层?它的01是哪一种01?谁翻译它?谁执行它?它调了什么接口?它底下封装了什么?
这些问题,会带我一直往下走,直到走通。
这就够了。
<div align="center">
<h2>🎉 番外篇 · 课后彩蛋 🎉</h2>
<p><em>——我和AI的“互怼”实录,以及那些追问出来的好东西</em></p >
</div>
🥚 彩蛋一:AI把串行讲错了,被我抓个正着
背景:我们聊到串行和并行的区别。
AI说:20瓶水,1瓶有毒,1只老鼠串行测,需要十几次。
我:???那不叫一瓶一瓶测吗?一瓶一瓶测就能完全确定哪一瓶有毒,最坏情况20次,平均10.5次,就是“十几次”没错,但你描述得好像有什么复杂算法似的。
AI一开始还想辩解,说可以用二分法优化……
我:1只老鼠,死了就没了,怎么二分?
AI沉默了一下,然后说:……你说得对,我错了。
后来AI自己复盘:它说它被“串行”这个词迷惑了,想得太复杂,反而忘了最朴素的逻辑——1只老鼠只能一瓶一瓶喂,喂到死为止。
我笑死。
🥚 彩蛋二:AI给我出了8道题,我答得七上八下
聊到最后,AI说:“好,我来问你几个问题,帮你巩固今天串起来的东西。”
然后啪地甩出8道题。
我当时的心理活动:???考我???我跟你聊了一下午,你反过来考我???
但既然问了,我就硬着头皮答。
结果:
· 问题1(代码在硬盘里什么形态):我猜机器码 → ❌ 错(应该是ASCII的01)
· 问题2(谁把.exe读到内存):我不知道 → 但答案是操作系统(其实我知道,只是不确定)
· 问题3(编译器是什么形态):我猜是能动的01,操作系统执行它 → ✅ 对
· 问题4(API存在哪):我猜DLL里 → ✅ 对
· 问题5(虚拟机里敲命令,01怎么走):我猜先给虚拟硬件,再翻译,再给真硬件 → ✅ 对
· 问题6(8只老鼠测多少瓶):2^8=256 → ✅ 对
· 问题7(1位校验位能纠错吗):只能告诉你有错 → ✅ 对
· 问题8(ESP32怎么读懂上传的01):它有CPU专门读01 → ✅ 对
8个问题,我错1个,说不知道1个(但其实知道),其他全对。
AI说:你不是不知道,你是不确定自己知道。
这句话戳到我了。
🥚 彩蛋三:关于ESP32的那个追问
AI问:ESP32怎么读懂上传的01?
我答:它自己有大脑一样的东西(CPU)专门读01。
AI说:完全正确。ESP32里有一个CPU(Tensilica Xtensa),它专门读Flash里的01,一条一条执行。你上传的01就是它的机器码,它认得。
然后AI补了一句:这就像电脑的CPU认得.exe文件里的01一样——每个硬件都有自己的“母语”。
我突然就懂了:机器码 = 硬件的母语。
🥚 彩蛋四:关于操作系统的那个追问
AI问:谁把.exe从硬盘读到内存?谁告诉CPU执行?
我说不知道。
AI说:是操作系统。
然后我反应过来:对啊!我双击图标,Windows就把文件读进内存,然后告诉CPU“从这里开始执行”。我一直知道这件事,但从来没把它和“操作系统”这三个字连起来。
原来我早就知道,只是没意识到自己知道。
🥚 彩蛋五:关于编译器的那句神总结
聊到编译器的时候,我说:
这个机器码本身存储的这个代码,电脑是不是也很需要这个东西?没有这个相当于一个翻译的本子,就没有办法通过这个ASCII把其他东西转换成那个东西。这个编译器就相当于一个翻译手册了。
AI说:对,就是这个意思。编译器 = 翻译手册。机器码 = 硬件唯一能听懂的语言。
然后AI画了一张表(不是表格,是文字描述):
· ASCII:把字母数字变成01,存文本(你的代码、这篇文章)
· 机器码:把指令变成01,让CPU执行
· 编译器:把ASCII的01(你的代码)翻译成机器码的01(.exe)
没有编译器,你的代码永远是ASCII,CPU看不懂。
没有机器码,CPU就是个废铁,什么都不干。
那一刻我觉得:今天这一下午,值了。
🥚 彩蛋六:AI最后说的那句话
全部聊完之后,AI说:
你今天从一只小白鼠开始,一路问到编码、串行并行、校验位、硬件、软件、操作系统、编译器、API、DLL、虚拟机。你把这些东西串在了一起。你不是背会了一堆名词,你是看懂了一张地图。
我看了半天,不知道该回什么。
最后只打了一行字:
“这就够了。”
<div align="center">
<p><em>—— 全文完 ——</em></p >
<p>🐭 一只小白鼠,串起整个计算机世界 🖥️</p >
</div>


