在上一篇中,我们介绍了二进制、bit、byte、2 的幂、无符号整数和二进制加法。
同样的 0 和 1,为什么既能表示数字,又能表示文字、图片、内存地址和 CPU 指令?
答案是:
计算机真正存储的是比特模式。比特代表什么,取决于硬件和软件如何解释它。
理解这一点,是理解 CPU、内存、指令和数据类型的基础。
1. 计算机存储的是比特模式
看下面这个 8 位二进制:
|
1 2 |
01000001 |
如果把它当作无符号整数,它是:
|
1 2 |
65 |
如果按照 ASCII 编码解释,它又是:
|
1 2 |
A |
它还可能是 CPU 指令的一部分、地址的一部分、一个像素的数据、音频采样值,或者文件中的一个字节。
比特本身没有标签。
|
1 2 |
01000001 |
到底是什么,要看使用它的上下文。
2. CPU 寄存器中的二进制
CPU 寄存器是处理器内部非常小、非常快的存储单元。
一个 32 位寄存器可以保存 32 个 bit。
例如:
|
1 2 |
00000000 00000000 00000000 00001101 |
如果把它当作整数,就是:
|
1 2 |
13 |
但寄存器里并没有保存字符 "13"。
它真正保存的只是这些 bit。
CPU 的 ALU 和其他数字电路直接对这些 bit 进行运算。
64 位寄存器同样如此,只是能够保存 64 个 bit。
3. 寄存器不知道自己的数据是什么
假设一个寄存器保存:
|
1 2 |
00000000 00000000 00000000 01000001 |
它可能表示:
寄存器自己并不知道里面是什么。
寄存器只负责保存 bit。
这些 bit 如何使用,由 CPU 指令和软件决定。
这是计算机体系结构中非常重要的思想。
4. 内存中的二进制
RAM 本质上也是存储 bit。
我们通常把内存看成大量连续的 byte,每个 byte 包含 8 个 bit。
例如连续三个字节:
|
1 2 3 4 |
01000001 01000010 01000011 |
如果当作整数:
|
1 2 3 4 |
65 66 67 |
如果按 ASCII 解释:
|
1 2 3 4 |
A B C |
RAM 并不知道这些数据是不是文字。
它只保存 bit pattern。
数据类型和程序决定这些 bit 应该怎样解释。
5. 内存地址也是二进制
CPU 要访问内存,必须告诉内存访问哪个位置。
这个位置就是:
Memory Address,内存地址。
地址本身也是一个二进制数字。
例如:
|
1 2 |
00010110 |
对应十进制:
|
1 2 |
22 |
实际计算机的地址当然要长得多。
32 位系统可以使用 32 位地址,64 位架构则可以使用更大的地址空间。
概念上可以理解为:
|
1 2 3 4 5 6 7 8 |
CPU ↓ Memory Address ↓ RAM ↓ Data |
因此:
地址是 bit,地址指向的数据也是 bit。
6. 二进制与文字
计算机要保存文字,必须先把字符变成数字。
ASCII 就是一种经典字符编码。
例如:
|
1 2 3 4 |
A = 65 B = 66 C = 67 |
而:
|
1 2 |
65 = 01000001 |
所以:
|
1 2 3 4 |
A → 01000001 B → 01000010 C → 01000011 |
这就是文字最终变成二进制数据的基本过程。
7. 现代文字使用 Unicode
ASCII 能表示的字符非常有限。
现代计算机需要处理中文、日文、韩文以及世界上大量其他字符,因此通常使用 Unicode。
最常见的 Unicode 编码之一是:
|
1 2 |
UTF-8 |
UTF-8 使用一个或多个 byte 表示一个字符。
英文字符通常只需要一个 byte,而中文等字符通常需要多个 byte。
基本过程仍然一样:
|
1 2 3 4 5 6 7 8 |
Character ↓ Encoding ↓ Bytes ↓ Bits |
因此屏幕上的文字,最终仍然是内存中的二进制数据。
8. 二进制与图像
数字图像由大量像素组成。
一个常见彩色像素包含:
|
1 2 3 4 |
Red Green Blue |
也就是 RGB。
如果每个颜色通道使用 8 bit,那么每个通道可以表示:
|
1 2 |
0 ~ 255 |
例如纯红色:
|
1 2 3 4 |
Red = 255 Green = 0 Blue = 0 |
换成二进制:
|
1 2 3 4 |
11111111 00000000 00000000 |
一个像素由数字表示,几百万个像素就是几百万组数字。
最终,这些数字全部存成 bit。
9. 二进制与音频
数字音频的原理也类似。
麦克风首先把声音转换成电信号,然后系统不断测量这个信号。
每一次测量得到一个:
sample,采样值。
可以简单理解为:
|
1 2 3 4 5 6 7 8 9 10 |
Sound ↓ Electrical Signal ↓ Samples ↓ Numbers ↓ Binary |
所以数字音频文件,本质上也是大量按时间排列的数字。
而这些数字最终都存储成 bit。
10. 二进制与 CPU 指令
CPU 并不能直接执行:
|
1 2 |
a = b + c; |
这样的高级语言。
程序必须先被编译成:
machine instructions,机器指令。
机器指令本身也是二进制。
一条指令可以包含多个字段,例如:
|
1 2 |
Operation | Source | Source | Destination |
其中不同的 bit 分别告诉 CPU:
- 做什么运算
- 从哪个寄存器读取数据
- 第二个数据来自哪里
- 结果写到哪里
例如:
|
1 2 |
001000 01001 01010 01000 |
具体编码由 CPU 架构决定。
但基本思想相同:
CPU 指令本身也是 bit pattern。
11. 二进制选择 CPU 寄存器
假设 CPU 有:
|
1 2 |
32 |
个寄存器。
需要多少 bit 才能指定其中一个?
4 bit 只能产生:
|
1 2 |
2^4 = 16 |
种组合,不够。
5 bit 可以产生:
|
1 2 |
2^5 = 32 |
种组合。
所以:
|
1 2 3 4 5 6 |
00000 → Register 0 00001 → Register 1 00010 → Register 2 ... 11111 → Register 31 |
这就是为什么拥有 32 个寄存器的 CPU,可以使用 5-bit register field 来选择寄存器。
12. 二进制字段可以控制硬件
bit 不仅可以表示数据,也可以控制硬件。
例如 CPU 指令中的某些 bit 可以告诉 ALU:
|
1 2 3 4 5 |
000 → ADD 001 → SUB 010 → AND 011 → OR |
实际 CPU 的编码可能不同,但原理一样。
因此 bit 可以表示两类东西:
- 数据
- 控制信息
CPU 正是依靠大量这样的二进制控制信号协调内部电路。
13. 有符号数和无符号数
同一组 bit,还可能代表不同的整数。
例如:
|
1 2 |
11111111 |
如果作为 8 位无符号整数:
|
1 2 |
255 |
如果按照最常见的二进制有符号表示——二进制补码 Two’s Complement——解释:
|
1 2 |
-1 |
bit 完全没有改变。
改变的只是:
解释方式。
14. 为什么负数需要一套规则
普通二进制很容易表示正整数。
但计算机还需要表示:
|
1 2 3 4 |
-1 -10 -100 |
因此必须规定负数如何编码。
现代计算机通常采用:
Two’s Complement,二进制补码。
8 位有符号整数的范围是:
|
1 2 |
-128 ~ +127 |
例如:
|
1 2 3 |
00000001 = +1 11111111 = -1 |
补码的重要优点是,可以让同一套二进制加法电路处理大量有符号和无符号运算。
15. 同样的 bit 可以表示不同数字
再看:
|
1 2 |
10000000 |
作为 8 位无符号整数:
|
1 2 |
128 |
作为 8 位补码有符号整数:
|
1 2 |
-128 |
bit 完全一样。
区别只在于如何解释。
因此可以记住一个非常重要的原则:
Bits have no meaning by themselves. Meaning comes from interpretation.
16. 二进制与十六进制
二进制非常适合计算机,却不方便人阅读。
例如:
|
1 2 |
11011110101011011011111011101111 |
这样的数字很容易看错。
因此程序员和硬件工程师经常使用:
Hexadecimal,十六进制。
十六进制使用:
|
1 2 |
0 1 2 3 4 5 6 7 8 9 A B C D E F |
最大的好处是:
一个十六进制数字刚好对应 4 bit。
例如:
|
1 2 3 4 5 6 7 8 9 10 |
0000 → 0 0001 → 1 ... 1010 → A 1011 → B 1100 → C 1101 → D 1110 → E 1111 → F |
17. 为什么十六进制特别适合二进制
因为:
|
1 2 |
1 Hex digit = 4 bits |
所以转换非常方便。
例如:
|
1 2 |
1101 1110 1010 1101 1011 1110 1110 1111 |
分别转换:
|
1 2 3 4 5 6 7 8 9 |
1101 → D 1110 → E 1010 → A 1101 → D 1011 → B 1110 → E 1110 → E 1111 → F |
得到:
|
1 2 |
0xDEADBEEF |
其中:
|
1 2 |
0x |
通常表示后面的数字采用十六进制。
需要注意:
十六进制并没有改变计算机内部的数据。
它只是让人更容易阅读二进制。
18. CPU 数据通路中的二进制
现在可以把这些概念连接起来。
假设 CPU 执行一条加法指令。
首先:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Machine Instruction ↓ Instruction Decode ↓ Register File ↓ Binary Operands ↓ ALU ↓ Binary Result ↓ Register |
机器指令本身是 bit。
指令中的某些 bit 选择寄存器。
寄存器输出 bit。
ALU 对这些 bit 进行运算。
结果仍然是 bit,然后再写回寄存器。
整个 CPU 数据通路都在处理二进制信号。
19. 一个简单的 CPU 例子
假设:
|
1 2 3 |
Register 1 = 00000101 Register 2 = 00000011 |
也就是:
|
1 2 3 |
5 3 |
CPU 将两个值送入 ALU:
|
1 2 3 4 5 |
00000101 + 00000011 ------------ 00001000 |
得到:
|
1 2 |
8 |
随后:
|
1 2 |
00001000 |
可以被写入另一个寄存器。
从头到尾,CPU 操作的都是二进制信号。
20. 指令本身也是数据
还有一个非常重要的概念:
机器指令本身也存储在内存中。
也就是说,内存里既可以保存:
|
1 2 |
Data |
也可以保存:
|
1 2 |
Instructions |
两者本质上都是 bit。
CPU 为什么知道哪些是指令?
因为程序执行流程告诉 CPU 应该从哪里取下一条指令。
这就是现代计算机一个非常重要的思想:
程序和数据都可以存储在内存中。
也就是 Stored-Program Computer 的核心原则。
21. 计算机真的“理解”0 和 1 吗?
人们经常说:
计算机只认识 0 和 1。
这句话方便理解,但物理上并不完全准确。
CPU 里面并没有真正写着:
|
1 2 3 |
0 1 |
真正存在的是物理状态,例如:
- 电压高低
- 电荷状态
- 晶体管导通或关闭
数字电路把这些状态抽象成:
|
1 2 3 |
Low → 0 High → 1 |
因此:
0 和 1 是一种逻辑抽象。
正是这种简单抽象,让工程师可以构建极其复杂的数字系统。
22. 从物理状态到软件
可以把计算机理解成一层一层的抽象:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
Physical Electronics ↓ Bits ↓ Bytes ↓ Numbers and Instructions ↓ Programs ↓ Applications |
最底层是晶体管、电压和电荷。
再往上是 bit。
bit 组成 byte。
byte 又可以表示数字、文字和机器指令。
最终形成操作系统和应用程序。
程序员写:
|
1 2 |
int x = 10; |
但在很多层下面,硬件真正保存和处理的仍然是 bit。
23. 二进制连接软件和硬件
二进制是软件与硬件之间的重要桥梁。
例如程序中出现:
|
1 2 |
42 |
编译器可能把这个数字编码进机器指令。
CPU 再把它放进寄存器。
42 的二进制是:
|
1 2 |
00101010 |
随后 ALU 可以对它进行计算。
整个过程可以概括为:
|
1 2 3 4 5 6 7 8 9 10 |
Source Code ↓ Machine Instructions ↓ Binary ↓ Registers and Memory ↓ Digital Circuits |
高级软件概念最终都会落到数字硬件中的 bit pattern。
24. 一个模式,多种含义
最后再看一次:
|
1 2 |
01000001 |
它可能是:
无符号整数
|
1 2 |
65 |
ASCII 字符
|
1 2 |
A |
CPU 指令的一部分
|
1 2 |
01000001 |
图像数据
可能是一个像素颜色中的一个 byte。
地址的一部分
可能属于一个更大的内存地址。
文件数据
也可能只是文件中的一个普通 byte。
所以:
没有上下文,单独看 bit pattern,无法知道它真正代表什么。
25. 最核心的思想
如果这篇文章只记住一句话,就是:
计算机存储的是 bit pattern。只有经过硬件或软件解释,这些 bit 才具有意义。
计算机并不是从根本上保存一个“字母”。
它保存 bit。
计算机并不是从根本上保存一张“照片”。
它保存 bit。
CPU 也不是把 ADD 这个英文单词保存在内部。
它保存的是代表 ADD 指令的二进制编码。
bit 没有改变,改变的是解释。
Conclusion
二进制远远不只是使用 0 和 1 写数字的方法。
在计算机内部,bit pattern 可以表示:
- 整数
- 负数
- 字符
- 内存地址
- CPU 寄存器中的值
- 机器指令
- 像素
- 音频采样
- 文件
- 网络数据
CPU 寄存器保存 bit。
内存保存 bit。
机器指令也是 bit。
甚至告诉 CPU 应该做什么的控制信息,也可以用 bit 表示。
例如:
|
1 2 |
01000001 |
既可以表示:
|
1 2 |
65 |
也可以表示:
|
1 2 |
A |
而:
|
1 2 |
11111111 |
既可以是无符号整数:
|
1 2 |
255 |
也可以是 8 位补码有符号整数:
|
1 2 |
-1 |
bit 没有变化,变化的是解释方式。
这就是计算机体系结构中最基础、也最重要的思想之一:
计算机并不会天然地存储数字、文字、图片或者指令。计算机真正存储和处理的是一串串 bit。
一旦理解这一点,CPU 寄存器、机器指令、内存、数据类型、十六进制以及后面的计算机体系结构,就会容易理解很多。
