建立共同基础
计算机基础
计算机组成、进制、编码、存储单位与位运算。
展开本篇目录
一、为什么学习计算机基础?
编写程序、配置环境和处理数据时,经常会遇到下面的问题:
- 内存和硬盘有什么区别?程序运行时 CPU 在做什么?
0b1010、10和0xA为什么表示同一个数?- 为什么一个汉字不一定只占两个字节?
- 100 Mbps 的网络为什么不等于每秒下载 100 MB?
- 位运算怎样检查一个设备状态或提取一段数据?
本教程从计算机组成出发,介绍数值、字符和文件在计算机中的基本表示方法,并通过手算与 Python 示例验证结果。
说明: 不会 Python 也可以先阅读概念和手算示例。代码用于辅助验证,不需要记住全部函数;涉及固定宽度数据时,会明确标注位数。
二、计算机的基本组成
2.1 五类基本部件
传统计算机组成常用运算器、控制器、存储器、输入设备和输出设备来描述。
| 部件 | 主要作用 | 示例 |
|---|---|---|
| 运算器 | 算术运算与逻辑运算 | CPU 中的算术逻辑单元 ALU |
| 控制器 | 组织指令执行,协调各部件 | CPU 中的控制逻辑 |
| 存储器 | 保存指令与数据 | 内存、缓存、外部存储设备 |
| 输入设备 | 将外部信息送入计算机 | 键盘、鼠标、传感器 |
| 输出设备 | 将处理结果送到外部 | 显示器、打印机、指示灯 |
现代 CPU 除运算和控制部件外,还包含寄存器、缓存等结构。网卡、触摸屏和存储设备等也可能同时承担输入与输出功能。
2.2 CPU、内存与硬盘
| 名称 | 主要用途 | 常见特点 |
|---|---|---|
| CPU | 执行指令、处理数据 | 内含一个或多个核心 |
| 寄存器 | 保存正在处理的少量数据与状态 | 容量小、访问快 |
| 缓存 Cache | 减少 CPU 等待主存的时间 | 常见 L1、L2、L3 等层级 |
| 内存 RAM | 保存运行中的程序和数据 | 常见主存断电后不保留数据 |
| SSD / HDD | 长期保存程序和文件 | 通常断电后仍能保留数据 |
“内存不够”和“硬盘空间不够”是两种问题。前者可能影响同时运行的程序和数据规模,后者影响能保存多少文件。
容量、速度和价格存在权衡,不能只看某一个指标判断性能。CPU 主频也不能单独决定不同计算机的运行速度。
2.3 程序怎样运行?
以运行一个数据处理程序为例:
|
这是简化过程。实际系统还涉及缓存、虚拟内存、中断和设备控制器等机制;Python 程序还需要解释器参与执行。
2.4 总线与操作系统
总线或其他互连用于传递数据、地址和控制信息。操作系统负责管理进程、内存、文件和设备,为应用程序提供运行与访问资源的接口。
“64 位系统”与处理器、指令集和软件的数据模型有关,不表示所有数据都占 64 位,也不表示一定能实际使用 2^64 字节内存。
三、bit、Byte 与二进制
3.1 bit:二进制位
bit 中文常称“位”或“比特”,表示一个二进制位置,其取值可以是 0 或 1。
电路可以用可区分的物理状态表示它们。逻辑上的 0 和 1 不应简单理解为所有设备中都完全相同的电压值。
3.2 Byte:字节
现代通用计算机中,1 Byte(字节,记作 B)通常等于 8 bit。本教程均按这一约定计算:
|
大小写有区别:b 常用于位,B 用于字节。描述数据速率时常见 bit/s、Mbps 和 MB/s。
3.3 n 位能表示多少种状态?
每位有两种取值,n 位共有 2^n 种组合。
|
如果按无符号整数解释,n 位的范围是 0 到 2^n - 1。例如 8 位无符号整数为 0~255,不是 1~256。
四、二、八、十、十六进制的表示
4.1 什么是进制?
进制规定每一位可用的数字,以及向高位进位的规则。基数为 r 的进制,每向左一位,位权乘以 r。
| 进制 | 基数 | 可用数字 | 示例 |
|---|---|---|---|
| 二进制 | 2 | 0、1 | (1010)₂ |
| 八进制 | 8 | 0~7 | (12)₈ |
| 十进制 | 10 | 0~9 | (10)₁₀ |
| 十六进制 | 16 | 0~9、A~F | (A)₁₆ |
十六进制中的 A、B、C、D、E、F 分别对应十进制 10、11、12、13、14、15,字母大小写均常见。
4.2 位权
十进制 253 可以展开为:
|
二进制整数从右向左的位权为:
|
4.3 编程中的前缀
Python 中常用下面的前缀区分整数写法:
|
这些写法表示同一个整数。进制改变的是表示方式,不改变数值本身。
注意: Python 的八进制前缀是 0o,不是直接在十进制数字前加 0。其他语言的规则可能不同。
五、其他进制转换为十进制
采用“各位数字乘位权,再求和”的方法。
5.1 二进制转十进制
|
5.2 八进制转十进制
|
5.3 十六进制转十进制
|
检查时注意数字是否合法,例如八进制不能含 8,二进制不能含 2。
六、十进制转换为其他进制
6.1 整数:除基取余,逆序排列
把非负十进制整数转换为 r 进制时,反复除以 r,记录余数,直到商为 0,再将余数从后往前排列。
以十进制 45 转二进制为例:
|
6.2 十进制转八进制
|
6.3 十进制转十六进制
|
余数大于 9 时,用 A~F 表示。数字 0 转换后仍为 0,不需要执行多次除法。
七、二进制、八进制与十六进制互转
7.1 二进制与八进制
因为 8 = 2³,一位八进制对应三位二进制。
| 八进制 | 二进制 | 八进制 | 二进制 |
|---|---|---|---|
| 0 | 000 | 4 | 100 |
| 1 | 001 | 5 | 101 |
| 2 | 010 | 6 | 110 |
| 3 | 011 | 7 | 111 |
整数部分从右向左每三位分组,不足三位在左侧补零:
|
反向转换时,将每个八进制数字展开成三位二进制:
|
7.2 二进制与十六进制
因为 16 = 2⁴,一位十六进制对应四位二进制。
| 十六进制 | 二进制 | 十六进制 | 二进制 |
|---|---|---|---|
| 0 | 0000 | 8 | 1000 |
| 1 | 0001 | 9 | 1001 |
| 2 | 0010 | A | 1010 |
| 3 | 0011 | B | 1011 |
| 4 | 0100 | C | 1100 |
| 5 | 0101 | D | 1101 |
| 6 | 0110 | E | 1110 |
| 7 | 0111 | F | 1111 |
|
7.3 八进制与十六进制
可以通过二进制中转:
|
补零只用于补齐分组,不改变数值。固定宽度的数据中,前导零还可以帮助表达位数,例如 00001111 表示按 8 位展示。
八、小数的进制转换
8.1 二进制小数转十进制
小数点右侧的位权为 2⁻¹、2⁻²、2⁻³……:
|
8.2 十进制小数转二进制
采用“乘二取整,顺序排列”,每次保留小数部分继续乘二:
|
整数和小数部分分别转换后组合。例如 (45.625)₁₀ = (101101.101)₂。
8.3 为什么浮点数存在误差?
并非所有有限十进制小数都能写成有限二进制小数,例如十进制 0.1 的二进制展开会无限重复。常见浮点类型用有限位数存储,所以可能产生近似误差。
|
近似比较的容差应结合任务选择。Python 的 int() 用于解析整数文本,不会直接把 "101.101" 解析成二进制小数。
九、整数表示:无符号数、补码与溢出
9.1 同一串位可以有不同含义
|
按 8 位无符号整数解释时是 255;按 8 位有符号补码解释时是 -1。解释数据前要先知道位宽、类型和规则。
9.2 有符号补码范围
n 位有符号补码整数的范围为 -2^(n-1) 到 2^(n-1)-1。
| 位数 | 无符号范围 | 有符号补码范围 |
|---|---|---|
| 8 | 0~255 | -128~127 |
| 16 | 0~65535 | -32768~32767 |
| 32 | 0~4294967295 | -2147483648~2147483647 |
9.3 负数补码示例
在 8 位前提下,求 -5 的补码:
|
也可以用 2⁸ - 5 = 251,再写成 8 位二进制。读取负数补码时,可将无符号值减去 2⁸,例如 251 - 256 = -5。
补码最高位可判断正负,但不能把剩余位直接当作负数的绝对值。
9.4 固定宽度与溢出
|
如果只保留低 8 位,结果是 00000000。真实语言和类型对溢出的处理不同,不能一律认为都会自动回绕;例如 C 的有符号整数溢出不能按普通回绕规则依赖。
Python 整数不使用固定 8 位或 32 位上限,会在内存允许范围内增长。需要模拟低 8 位时可以使用 value & 0xFF。
十、存储容量与数据速率换算
10.1 十进制单位
十进制前缀按 1000 逐级换算,千的规范符号为小写 k:
| 单位 | 字节数 |
|---|---|
| 1 kB | 1000 B |
| 1 MB | 1000² B = 1000000 B |
| 1 GB | 1000³ B = 1000000000 B |
| 1 TB | 1000⁴ B |
日常也常见 KB 写法,有些软件还用 KB、MB、GB 标注按 1024 换算的数值,因此需要确认实际约定。
10.2 二进制单位
二进制前缀按 1024 逐级换算:
| 单位 | 字节数 |
|---|---|
| 1 KiB | 1024 B |
| 1 MiB | 1024² B = 1048576 B |
| 1 GiB | 1024³ B = 1073741824 B |
| 1 TiB | 1024⁴ B |
为了避免歧义,本文用 kB、MB、GB 表示十进制,用 KiB、MiB、GiB 表示二进制。
10.3 换算示例
|
标称 1 TB 的磁盘,按二进制换算约为 931.32 GiB,约为 0.9095 TiB。格式化、分区和系统预留等还可能进一步影响可用容量。
10.4 Mbps 与 MB/s
|
这是按标称速率换算的数值。实际文件下载速度还受协议开销、服务器、网络质量和存储速度等影响。
以稳定 10 MB/s 下载 1 GB 数据,理想耗时:
|
换算前确认位、字节、十进制与二进制单位,不能只看“兆”这个口头说法。
十一、ASCII:字符与数值的对应
11.1 ASCII 是什么?
ASCII 定义了 128 个编码位置,用 7 位表示,范围为十进制 0~127,包括英文字母、数字字符、标点和控制字符。
在现代以 8 位字节存储 ASCII 文本的环境中,一个 ASCII 字符通常占 1 字节,最高位为 0。
11.2 常见字符
| 字符 | 十进制值 | 十六进制值 | 说明 |
|---|---|---|---|
| NUL | 0 | 00 | 空字符,不是可见数字 0 |
| TAB | 9 | 09 | 水平制表 |
| LF | 10 | 0A | 换行控制字符 |
| CR | 13 | 0D | 回车控制字符 |
| 空格 | 32 | 20 | 普通空格 |
0 |
48 | 30 | 数字字符 0 |
9 |
57 | 39 | 数字字符 9 |
A |
65 | 41 | 大写 A |
Z |
90 | 5A | 大写 Z |
a |
97 | 61 | 小写 a |
z |
122 | 7A | 小写 z |
数字 5 与字符 '5' 不同:前者是数值,后者在 ASCII 中对应数值 53,即十六进制 35。
11.3 控制字符与换行
Linux 文本常用 LF,Windows 文本常用 CRLF 作为行结束方式。两者占用的字节数可能不同,处理跨平台文本时要注意。
ASCII 不能表示汉字。“扩展 ASCII”没有唯一统一的 256 字符对应表,具体解释要看所用代码页或编码。
十二、Unicode 与 UTF 编码
12.1 字符、码点与字节
Unicode 为大量文字和符号规定码点,并定义相关文本处理规则。码点常写成 U+ 加十六进制数字。
| 字符 | Unicode 码点 | 十进制值 |
|---|---|---|
A |
U+0041 | 65 |
中 |
U+4E2D | 20013 |
😀 |
U+1F600 | 128512 |
码点是编号,编码形式规定如何把可编码的 Unicode 标量值变成代码单元序列,再以字节保存。Unicode 不等于“所有字符统一占两个字节”。
12.2 UTF-8、UTF-16 与 UTF-32
下表按一个 Unicode 标量值计算,不含 BOM 和文件格式额外内容:
| 编码 | 基本特点 | A |
中 |
😀 |
|---|---|---|---|---|
| UTF-8 | 变长,ASCII 范围兼容 ASCII | 1 B | 3 B | 4 B |
| UTF-16 | 使用一个或两个 16 位代码单元 | 2 B | 2 B | 4 B |
| UTF-32 | 一个 32 位代码单元 | 4 B | 4 B | 4 B |
UTF-8 对 Unicode 标量值使用 1~4 字节;UTF-16 并不总是两个字节。UTF-16、UTF-32 保存为字节时还要处理字节序。
12.3 同一个“字符”可能有不同计数方式
视觉上的一个字符可能由多个码点组成,例如字母与组合重音,或一些表情序列。
Python 的 len(str) 通常统计码点数量,不是字节数,也不一定等于用户看到的字符数量。文件字节数则取决于编码、换行、BOM 等因素;Python 对象的内存占用还包含对象开销。
12.4 BOM 和其他编码
BOM 是某些 Unicode 文本开头使用的标记,可帮助识别字节序或编码。UTF-8 不需要通过 BOM 判断字节序,但文件仍可能带 UTF-8 BOM。
历史或特定场景还会遇到 GBK、GB18030 等编码。它们与 UTF-8 规则不同,读取时需要与文件实际编码一致。
十三、编码、解码与乱码
13.1 编码和解码的方向
|
Python 示例:
|
13.2 为什么会乱码?
写入和读取时使用不同规则,可能显示错误字符,也可能直接报解码错误。
|
不是所有错误编码组合都会立刻报错,所以“程序没报错”不等于文本解码正确。
13.3 文件读写
|
这会创建或覆盖练习文件。遇到乱码时先确认原始编码、读取方式和显示环境;不要把忽略解码错误当成通用修复方法,否则可能丢失信息。
十四、位运算:按位与、或、异或、取反
位运算逐个处理整数二进制位。以下先用非负整数和固定 8 位示意图说明。
14.1 真值表
| a | b | 与 a & b |
或 a | b |
异或 a ^ b |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
14.2 按位与 &
两位都为 1,结果才为 1:
|
常用于保留特定位或检查标志位。
14.3 按位或 |
至少一位为 1,结果为 1:
|
常用于将某些位置为 1。
14.4 按位异或 ^
两位不同为 1,相同为 0:
|
常用于翻转指定位。Python 中 ^ 不是乘方,乘方使用 **。
14.5 按位取反 ~
固定 8 位示意:
|
Python 整数的位运算按具有无限符号扩展的补码模型理解,~x == -x - 1:
|
因此 ~12 不能直接解释成 8 位无符号数 243,必须明确位宽和掩码。
十五、移位、掩码与标志位
15.1 左移和右移
|
对 Python 的非负整数,左移 n 位等于乘 2^n,右移 n 位等于除以 2^n 后向下取整。
|
Python 负整数右移会保留符号含义,例如 -3 >> 1 为 -2。固定宽度语言的移位还受类型和位数限制,不要直接套用所有 Python 规则。
15.2 位编号和掩码
最低有效位从 0 开始编号:
|
上面只有第 3 位为 1,对应 1 << 3,即十进制 8。掩码是一组用于选择或修改特定位的二进制位。
| 操作 | Python 写法 |
|---|---|
| 检查第 k 位是否为 1 | (value & (1 << k)) != 0 |
| 将第 k 位置 1 | value | (1 << k) |
| 将第 k 位清零 | value & ~(1 << k) |
| 翻转第 k 位 | value ^ (1 << k) |
| 取低 4 位 | value & 0x0F |
| 取第 4~7 位 | (value >> 4) & 0x0F |
15.3 用一字节保存多个状态
假设最低三位分别表示“就绪”“报警”“正在采集”:
|
位运算 &、| 与逻辑运算 and、or 不同,判断表达式中建议用括号明确顺序。
十六、字节序与数据解释
16.1 一个数可以占多个字节
十六进制数 0x1234 需要两个字节表示,分别是 0x12 和 0x34。按内存地址从低到高排列:
| 字节序 | 字节排列 |
|---|---|
| 大端 Big-endian | 12 34,高位字节在前 |
| 小端 Little-endian | 34 12,低位字节在前 |
字节序讨论多字节值的字节排列,不是把每个字节内部的二进制数字倒过来。
16.2 Python 验证
|
读取串口、网络协议、图像或二进制文件时,需要确认字段长度、字节序、有无符号和编码规则,不能只根据字节外观猜测内容。
例如文本 "12" 的 UTF-8 字节为 31 32,整数 12 按一个无符号字节存储时为 0C,含义相近但表示完全不同。
十七、使用 Python 验证进制与编码
17.1 整数转进制字符串
|
08b 表示二进制、至少宽 8 位、不足补零,不表示把整数限制为 8 位。值超过 255 时,仍会显示更多位。
17.2 进制字符串转整数
|
17.3 字符和码点转换
|
ord() 接受单个字符,返回码点;它的结果不是该字符的 UTF-8 字节。获取字节应使用 .encode("utf-8")。
十八、一个综合示例
下面模拟设备发送的数据包。协议是本教程自定义的练习格式,不对应具体设备。
18.1 数据格式
|
| 字段 | 长度 | 约定 |
|---|---|---|
| 状态 | 1 B | bit0 就绪、bit1 报警、bit2 正在采集,其余为 0 |
| 采样值 | 2 B | 大端无符号整数,单位为 0.1 摄氏度 |
| 标签 | 剩余字节 | UTF-8 文本 |
18.2 手工分析
- 状态
0x05 = 00000101₂,表示就绪、正在采集,没有报警。 - 采样值
0x012C = 1×256 + 44 = 300。 - 按约定缩放:
300 × 0.1 = 30.0 摄氏度。 - 标签字节
E4 B8 AD按 UTF-8 解码为“中”。 - 整个数据包长
6 B = 48 bit,不包含额外协议头和传输开销。
18.3 编程验证
将下面代码保存为 decode_packet.py:
|
运行:
|
预期结果应与手算一致。该示例只处理已知合法样例,接收真实数据时还需校验长度、字段范围、文本编码及协议规定的校验信息。
十九、常见问题与易错点
| 问题 | 正确认识 |
|---|---|
| 内存与硬盘都是容量,是否能互换? | 用途、访问方式和性能不同,不能直接等同 |
| 8 位有 256 种状态,最大值是否为 256? | 无符号整数从 0 开始,最大值是 255 |
0x10 是否为十进制 10? |
是十六进制 10,数值为十进制 16 |
| 十进制转整数进制,余数是否顺序读取? | 应逆序读取;小数乘基取整才是顺序读取 |
1 KB 是否一定为 1024 B? |
写法存在混用,先确认约定;KiB 明确为 1024 B |
| 100 Mbps 是否等于 100 MB/s? | 位与字节不同,标称换算为 12.5 MB/s |
字符 0 是否等于 NUL? |
字符 0 的 ASCII 值为 48,NUL 为 0 |
| 一个汉字是否固定占 2 B? | 取决于编码和具体字符,UTF-8 常见汉字为 3 B |
| Unicode 是否等于 UTF-8? | Unicode 定义字符码点等规则,UTF-8 是其编码形式之一 |
len(text) 是否为文本文件大小? |
它通常计码点,编码后的字节数需单独计算 |
~12 是否就是 243? |
在 Python 中是 -13,取低 8 位才得到 243 |
^ 是否表示乘方? |
Python 中表示按位异或,乘方是 ** |
| 格式化为 8 位是否会自动截断? | 不会,显示宽度与存储位宽不同 |
| 相同字节是否一定代表相同数据? | 还要知道类型、位宽、字节序和编码 |
二十、练习
建议先手算,再用程序验证,并写下换算过程。
20.1 计算机组成
- 分别说明 CPU、内存、SSD 的用途。
- 描述一个程序从文件到运行结果的简化过程。
- 说明为什么“内存 16 GB”和“磁盘 512 GB”不能当作同一指标相加。
20.2 进制转换
- 将
(110010)₂转成十进制、八进制、十六进制。 - 将
(125)₁₀转成二进制、八进制、十六进制。 - 将
(3A)₁₆转成二进制与十进制。 - 将
(237)₈转成二进制与十六进制。 - 将
(0.375)₁₀转成二进制小数。 - 判断
(102)₂、(89)₈、(1G)₁₆是否是合法表示,解释原因。
20.3 数值与容量
- 计算 12 位无符号整数的最大值。
- 写出
-6的 8 位补码,并解释11111010的有符号值。 - 将
4096 B换算为 KiB,将2 MiB换算为 B 和 bit。 - 分别计算
1 GB和1 GiB的字节数,求两者之差。 - 按十进制单位,计算 200 Mbps 对应的 MB/s 理论数值。
20.4 编码与位运算
- 查询
B和b的 ASCII 值及十六进制表示。 - 计算
"Hi中"的码点数与 UTF-8 字节数。 - 判断“UTF-16 中每个字符一定为 2 B”是否正确。
- 计算
12 & 5、12 | 5、12 ^ 5、5 << 2、20 >> 1。 - 对
value = 0b10110010,提取低四位,将第 0 位置 1,将第 7 位清零。 - 将
0x1234按小端写成两个字节,并说明用错误字节序读取会得到什么值。 - 修改综合示例,使报警位也为 1,检查其他字段是否保持不变。
20.5 部分参考答案
| 题目 | 参考结果 |
|---|---|
(110010)₂ |
十进制 50,八进制 62,十六进制 32 |
(125)₁₀ |
二进制 1111101,八进制 175,十六进制 7D |
(3A)₁₆ |
二进制 00111010,十进制 58 |
(237)₈ |
二进制 10011111,十六进制 9F |
(0.375)₁₀ |
(0.011)₂ |
| 12 位无符号最大值 | 4095 |
-6 的 8 位补码 |
11111010 |
4096 B |
4 KiB |
2 MiB |
2097152 B,16777216 bit |
1 GiB - 1 GB |
73741824 B |
| 200 Mbps | 25 MB/s,未考虑实际开销 |
B、b |
66 / 0x42;98 / 0x62 |
Hi中 |
3 个码点,5 个 UTF-8 字节 |
| 五个位运算题 | 4、13、9、20、10 |
10110010 的低四位 |
0010,即 2 |
| 将原值第 0 位置 1 | 10110011 |
| 将原值第 7 位清零 | 00110010 |
0x1234 小端字节 |
34 12,若误按大端读取得到 0x3412,即 13330 |
| 数据包增加报警位 | 状态从 05 改为 07 |
二十一、常用知识速查表
| 知识点 | 规则或示例 |
|---|---|
| 1 字节 | 本教程按 8 bit |
| n 位组合数 | 2^n |
| n 位无符号范围 | 0~2^n-1 |
| n 位有符号补码范围 | -2^(n-1)~2^(n-1)-1 |
| 其他进制转十进制 | 按位权展开求和 |
| 十进制整数转 r 进制 | 除 r 取余,逆序排列 |
| 十进制小数转二进制 | 乘 2 取整,顺序排列 |
| 二进制与八进制 | 每 3 位一组 |
| 二进制与十六进制 | 每 4 位一组 |
| 1 MB / 1 MiB | 1000000 B / 1048576 B |
| bit/s 转 B/s | 数值除以 8 |
| ASCII | 7 位,128 个编码位置 |
| UTF-8 | 每个 Unicode 标量值使用 1~4 B |
| 编码 / 解码 | 文本到字节 / 字节到文本 |
| 按位与 / 或 / 异或 / 取反 | & / ` |
| 保留低 8 位 | value & 0xFF |
| 左移 / 右移 | << / >> |
| Python 整数转进制字符串 | bin()、oct()、hex() |
| 进制字符串转整数 | int(text, base) |
| 字符与码点 | ord()、chr() |
| 大端 / 小端 | 高位字节在前 / 低位字节在前 |
二十二、相关学习资料
- Unicode 官方技术介绍:理解 Unicode、码点及 UTF 编码的关系,英文。
- Python 官方中文 Unicode 指南:结合字符串、字节和文件读写理解编码。
- RFC 20:ASCII:ASCII 表与历史网络交换说明,英文。
- RFC 3629:UTF-8:UTF-8 字节序列规则,英文,适合进阶查阅。
- NIST:二进制前缀:区分十进制与二进制容量单位,英文。
- Python 整数与位运算说明:查阅整数类型、位运算及字节转换;注意选择对应 Python 版本。