【深入理解计算机系统】第二章第一节(信息存储)笔记

Chapter 2:信息的表示和处理(§2.1 信息存储)

预习完成:2026-06-03 | §2.1 共 9 小节 + 6 个 C 初学者专栏 + 14 个知识点


CSAPP

  • [Chapter 2:信息的表示和处理(§2.1 信息存储)](#Chapter 2:信息的表示和处理(§2.1 信息存储))
    • [§2.1 信息存储 --- 核心概念](#§2.1 信息存储 — 核心概念)
      • 基本概念
      • [2.1.1 十六进制表示法](#2.1.1 十六进制表示法)
      • [2.1.2 字数据大小](#2.1.2 字数据大小)
      • [2.1.3 寻址和字节顺序](#2.1.3 寻址和字节顺序)
      • [2.1.4 表示字符串](#2.1.4 表示字符串)
      • [2.1.5 表示代码](#2.1.5 表示代码)
      • [2.1.6 布尔代数简介](#2.1.6 布尔代数简介)
      • [2.1.7 C 语言中的位级运算](#2.1.7 C 语言中的位级运算)
      • [2.1.8 C 语言中的逻辑运算](#2.1.8 C 语言中的逻辑运算)
      • [2.1.9 C 语言中的移位运算](#2.1.9 C 语言中的移位运算)
    • [C 初学者专栏速查(§2.1 共 8 个)](#C 初学者专栏速查(§2.1 共 8 个))
    • 易错点
    • 与其他章节的联系
  • [Chapter 2 术语表(§2.1 信息存储)](#Chapter 2 术语表(§2.1 信息存储))
    • [§2.1 引言](#§2.1 引言)
    • [2.1.1 十六进制表示法](#2.1.1 十六进制表示法)
    • [2.1.2 字数据大小](#2.1.2 字数据大小)
    • [2.1.3 寻址和字节顺序](#2.1.3 寻址和字节顺序)
    • [2.1.4 表示字符串](#2.1.4 表示字符串)
    • [2.1.5 表示代码](#2.1.5 表示代码)
    • [2.1.6 布尔代数简介](#2.1.6 布尔代数简介)
    • [2.1.7 C 语言中的位级运算](#2.1.7 C 语言中的位级运算)
    • [2.1.8 C 语言中的逻辑运算](#2.1.8 C 语言中的逻辑运算)
    • [2.1.9 C 语言中的移位运算](#2.1.9 C 语言中的移位运算)

§2.1 信息存储 --- 核心概念

基本概念

概念 解释
bit(位) 最小信息单位,只有 0 或 1
byte(字节) 8 个 bit 组成的最小可寻址单位,CPU 每次至少存取 1 字节
虚拟内存(virtual memory) 从程序视角,内存就是一个巨大的字节数组(byte array)
地址(address) 每个字节的唯一标识,从 0 开始编号
虚拟地址空间 所有可能地址的集合;32 位系统 = 0 ~ 2³²-1(4GB),64 位系统 = 0 ~ 2⁶⁴-1(16EB)
指针 值 = 某个内存块的第一个字节的虚拟地址;类型 = 告诉编译器那个位置存的是什么

核心原则:信息 = 位 + 上下文。 同一串 0/1,不同解释 = 不同含义(整数、浮点数、指令、字符串等)。C 编译器的类型信息只存在于编译时,运行时只有字节。


2.1.1 十六进制表示法

为什么用十六进制?

进制 问题
二进制 100011110011... 太冗长,人眼看瞎
十进制 和 bit 转换麻烦(10 不是 2 的幂)
十六进制 16 = 2⁴,每 4 个 bit ⇔ 1 个 hex 数字,完美!

常用对应关系(必须背熟):

Hex 二进制 十进制 Hex 二进制 十进制
0 0000 0 8 1000 8
1 0001 1 9 1001 9
2 0010 2 A 1010 10
3 0011 3 B 1011 11
4 0100 4 C 1100 12
5 0101 5 D 1101 13
6 0110 6 E 1110 14
7 0111 7 F 1111 15

转换规则:

转换方向 方法
二进制 → Hex 从右往左,每 4 bit 一组,查表
Hex → 二进制 每个 hex 数字展开成 4 bit
十进制 → Hex 反复除以 16,从下往上读余数
Hex → 十进制 每位 × 16 的对应次幂,求和

2ⁿ 快捷转换法:

n = i + 4j(i ∈ {0, 1, 2, 3}),开头数字由 i 决定,后面跟 j 个 0。

i 开头 hex 示例
0 1 n=8 → 1×16² = 0x100
1 2 n=9 → 2×16² = 0x200
2 4 n=10 → 4×16² = 0x400
3 8 n=11 → 8×16² = 0x800

2.1.2 字数据大小

字长(word size)= 指针的标称大小,决定虚拟地址空间的上限。

字长 地址空间 指针大小 主流年代
32 位 4 GB 4 字节 1980--2010
64 位 16 EB 8 字节 2010--至今

关键区分:"32 位程序 / 64 位程序"指的是如何编译的,不是运行的机器类型。 gcc -m32 → 32 位程序(两种机器都能跑),gcc -m64 → 64 位程序(只能 64 位机器跑)。

C 数据类型字节数(32 位 vs 64 位):

类型 32 位 64 位 是否随字长变化
char 1 1
short 2 2
int 4 4
long 4 8
char*(指针) 4 8
float 4 4
double 8 8
int32_t 4 4 ❌(固定大小)
int64_t 8 8 ❌(固定大小)

移植陷阱:

错误假设 32 位 64 位
int 可以存指针 ✅ 都是 4 字节 ❌ int=4, 指针=8 → 截断
long = 指针大小 ✅ 都是 4 ✅ 都是 8
指针大小一定 ✅ 4 字节 ❌ 变 8 字节

最佳实践:

做法
明确需要固定大小时 int32_tint64_t,不用 intlong
不确定 char 符号时 显式写 signed charunsigned char
需要可移植的全 1 掩码 ~0 而不是 0xFFFFFFFF
需要可移植尺寸信息 sizeof(T) 而不是硬编码数字

2.1.3 寻址和字节顺序

多字节对象:连续存储,地址 = 所用字节中最小的那个。

小端法 vs 大端法:

int x = 0x01234567 存放在地址 0x100 为例:

0x100 0x101 0x102 0x103 规则
小端(Little Endian) 67 45 23 01 低位字节在低地址
大端(Big Endian) 01 23 45 67 高位字节在低地址

实际分布:

端序 代表硬件 / 系统
小端 Intel x86/x86-64,ARM(Android / iOS)
大端 IBM 大型机,旧 Sun SPARC
双端(可配置) 某些 ARM 芯片(但 OS 固定后就不可变)

字节顺序的选择没有技术上的优劣之分------就像鸡蛋从哪头剥一样,选一个然后始终如一即可。

字节顺序在三种情况下会出问题:

情况 问题 解决
① 网络传输 小端机器发数据给大端机器(或反之),接收方字节反序 统一网络字节序(第 11 章)
② 阅读反汇编 小端机器上 hex dump 显示的数字是反的,需要倒过来读 读 hex dump 时注意目标机器的端序
③ 用强制类型转换规避类型系统 (byte_pointer) &x 看到原始字节,端序会影响所见 show_bytes 时注意端序

show_bytes --- 核心工具函数:

c 复制代码
typedef unsigned char *byte_pointer;  // "一次只读1字节"的指针

void show_bytes(byte_pointer start, size_t len) {
    for (size_t i = 0; i < len; i++)
        printf(" %.2x", start[i]);   // 逐字节以 hex 打印
}

void show_int(int x) {
    show_bytes((byte_pointer) &x, sizeof(int));  // 强制类型转换!
}

核心技巧:(byte_pointer) &x --- 骗编译器,把 int 地址强行当字节序列看待。

同一数值 12345 在不同机器上的字节表示(图 2-6):

int (12345) float (12345.0) 结论
小端机器 39 30 00 00 00 e4 40 46 int 和 float 编码完全不同
大端机器 00 00 30 39 46 40 e4 00 同类型下只是字节反序
跨平台 数值相同,端序可能不同 数值相同,端序可能不同 指针值完全因机器/OS 而异

2.1.4 表示字符串

C 字符串 = 以 null 字符(0x00)结尾的字符数组。

复制代码
"12345" → 字节:31 32 33 34 35 00
            '1'  '2'  '3'  '4'  '5'  '\0'

数字字符 'x' 的 ASCII 码 = 0x3x'3'=0x33, '9'=0x39)。

字符串 vs 二进制数据的跨平台性:

数据类型 跨平台性 原因
字符串(ASCII) ✅ 完全一致 每个字符 1 字节,无端序问题
二进制数值(int / float) ⚠️ 可能反序 多字节,端序影响
机器代码 ❌ 完全不同 不同 CPU 指令集不兼容

核心结论:文本数据比二进制数据具有更强的平台独立性。


2.1.5 表示代码

同一函数编译后,不同平台上生成的机器代码完全不同。

c 复制代码
int sum(int x, int y) { return x + y; }
平台 机器代码字节
Linux 32 55 89 e5 8b 45 0c 03 45 08 c9 c3
Windows 55 89 e5 8b 45 0c 03 45 08 5d c3
Sun 81 c3 e0 08 90 02 00 09
Linux 64 55 48 89 e5 89 7d fc 89 75 f8 03 45 fc c9 c3

从机器的角度看,程序仅仅只是字节序列。机器没有关于原始源程序的任何信息。


2.1.6 布尔代数简介

四种基本运算:

运算 C 符号 规则 口诀
NOT(非) ~ 1→0, 0→1 反转
AND(与) & 两个都 1 才 1 全真才真
OR(或) ` ` 至少一个 1 就是 1
XOR(异或) ^ 两个不一样才是 1 不同为真

位向量运算:每一位独立算,互不影响。

复制代码
a   = [0 1 1 0]
b   = [1 1 0 0]
a&b = [0 1 0 0]
a|b = [1 1 1 0]
a^b = [1 0 1 0]
~b  = [0 0 1 1]

2.1.7 C 语言中的位级运算

运算符 含义 使用技巧
& 按位与 掩码:用来提取 / 清零指定位
` ` 按位或
~ 按位取反 翻转所有位
^ 按位异或 翻转指定位(和 1 异或 = 翻转)、判断两数是否相等

求值步骤:hex → 二进制 → 逐位算 → 回 hex。

掩码(Mask)------位级运算最常用的模式:

操作 表达式 效果
提取最低字节 x & 0xFF 只保留低 8 位,其他清零
置位某些位 `x 0x0F`
翻转某些位 x ^ 0x0F 低 4 位翻转,其他不变
生成全 1 掩码 ~0 不管字长多少,全 1(可移植)

2.1.8 C 语言中的逻辑运算

位级运算 vs 逻辑运算(极易混淆!):

位级运算(bitwise) 逻辑运算(logical)
符号 & ` ~` `^`
操作对象 每个 bit 独立算 整个值视为"真"或"假"
规则 0=0, 1=1 0=假(FALSE),非 0=真(TRUE)
返回结果 任意数值 只返回 0 或 1
短路求值 ❌ 两边都算 ✅ 左边能确定结果则跳过右边

短路求值示例:

表达式 左值确定结果时 安全性
a && 5/a a=0 → 假 → 不执行 5/a ✅ 安全,不会除零
a & 5/a 无论 a 是什么都算 5/a ❌ 危险,a=0 时崩
p && *p++ p=NULL → 假 → 不执行 *p++ ✅ 安全,不会空指针解引用

!!x = 将任意值归一化为 0 或 1(非零→1,零→0)。

对比测试:x=0x66, y=0x39

表达式 结果 原因
x & y 0x20 逐位 AND:0x66 & 0x39 = 0x20
x && y 0x01 两个都非零 → 真 → 1
`x y` 0x7F
`x y`

2.1.9 C 语言中的移位运算

移位 方向 补位 等价效果
x << k 左移 右边补 k 个 0 x × 2 k x \times 2^k x×2k
x >> k(逻辑右移) 右移 左边补 0 无符号数专用
x >> k(算术右移) 右移 左边补符号位(最高位是啥补啥) 有符号数保持正负号
复制代码
示例:x = [10010101]
逻辑右移 4 位:  [0000 1001]    ← 左边补 0
算术右移 4 位:  [1111 1001]    ← 左边补符号位(MSB=1 所以补 1)

C 语言的坑:

问题 说明
有符号数右移类型未定义 C 标准不规定用逻辑还是算术右移(实际几乎所有编译器用算术右移)
无符号数右移 明确规定:必须是逻辑右移
移位量 ≥ 字长 未定义行为!实际多数机器算 k mod w,但不要依赖
移位优先级低于加减 1 << 2 + 3 << 4 = (1 << (2+3)) << 4(1<<2) + (3<<4)

Java 对比: Java 明确定义 >> = 算术右移,>>> = 逻辑右移,不存在歧义。


C 初学者专栏速查(§2.1 共 8 个)

# 专栏标题 核心内容
1 C 语言中指针的作用 指针 = 值(地址)+ 类型(指向什么);第 3 章深入机器级实现
2 声明指针 T *p; 声明一个指向 T 类型的指针
3 使用 typedef 命名数据类型 typedef 原名 新名; 给复杂类型起小名
4 使用 printf 格式化输出 %d(整数), %f(浮点), %x(hex), %c(字符), %.2x(2位hex)
5 指针和数组 start[i] 可以用在指针上,和遍历数组一模一样
6 指针的创建和间接引用 &x 取地址创建指针,*p 解引用取数据;强制类型转换不改变真实指针
7 C 语言版本和编译选项 -std=c89, -std=c99, -std=c11;书默认基于 C90
8 移位运算的优先级陷阱 加减法优先级 > 移位 → 拿不准就加括号!

易错点

  1. 类型信息只存在于编译时,运行时只有字节。 写类型转换时记住:机器不关心类型,只看见 bit。(§2.1 引言)
  2. "32 位程序"说的是编译方式,不是机器类型。 64 位机器能跑 32 位程序(向后兼容),反之不行。(§2.1.2)
  3. int 在 64 位系统上还是 4 字节。 只有 long 和指针从 4 变 8。很多人错误以为 int 会变 8。(§2.1.2)
  4. char 的符号不明确。 C 标准不保证 char 是有符号还是无符号------显式写 signed charunsigned char。(§2.1.2)
  5. 小端机器上读 hex dump,多字节数值是反的。 hex dump 显示顺序 = 内存地址从小到大,低位字节在低地址(小端)= 先显示。(§2.1.3)
  6. 位级运算 ≠ 逻辑运算。 & vs &&:符号完全不同、返回结果完全不同、是否短路完全不同。(§2.1.8)
  7. 有符号数右移的结果不可移植。 C 标准不规定用哪种右移------如果真需要可移植,用无符号数。(§2.1.9)
  8. 移位量超出字长 = 未定义行为。 不要写 x << 40(32 位 int),即使"实际会 mod 32"也别依赖。(§2.1.9)
  9. 加减法优先级比移位高。 1<<2+3<<4(1<<2)+(3<<4),拿不准就加括号。(§2.1.9)

与其他章节的联系

本章概念 展开章节
虚拟内存 ≠ 物理内存 第 9 章 虚拟内存
指针在机器级的表示和实现 第 3 章(3.10.1 节)
网络字节序(大端) 第 11 章 网络编程
反汇编器与机器代码阅读 第 3 章 程序机器级表示
指针和数组的紧密联系 第 3 章(3.8 节)
布尔代数在数字系统中的应用 第 4 章 处理器体系结构
int 和 float 编码完全不同 --- 补码 vs IEEE 754 §2.2--§2.4
算术右移的作用(保持符号位) §2.2 整数表示(补码运算)

Chapter 2 术语表(§2.1 信息存储)

四色标注:⚫ 黑色 = 事实 / 定义 | 🔵 蓝色 = 核心概念 | 🔴 红色 = 易错点 / 陷阱 | 🟢 绿色 = 后续章节关联


§2.1 引言

术语 英文 解释 标注
位(比特) bit 最小信息单位,取值 0 或 1 ⚫ 事实
字节 byte 8 个 bit 组成的最小可寻址单位,CPU 每次至少存取 1 字节 ⚫ 事实
虚拟内存 virtual memory 从机器级程序视角看,内存就是一个巨大的字节数组 🔵 核心
地址 address 每个字节的唯一数字标识 ⚫ 事实
虚拟地址空间 virtual address space 所有可能地址的集合;实际由 DRAM + 磁盘 + OS 联合实现 🔵 核心
程序对象 program object 程序数据、指令和控制信息,在内存中就是字节块 ⚫ 事实

2.1.1 十六进制表示法

术语 英文 解释 标注
十六进制 hexadecimal (hex) 以 16 为基数的计数法,用 0-9A-F 表示 16 个值,每 4 个 bit 对应 1 个 hex 数字 ⚫ 事实
0x / 0X 前缀 0x prefix C 语言中十六进制常量的前缀,如 0x7AF ⚫ 事实

2.1.2 字数据大小

术语 英文 解释 标注
字长 word size 指针数据的标称大小;决定虚拟地址空间上限(32 位 = 4GB,64 位 = 16EB) 🔵 核心
int32_t / int64_t fixed-size types ISO C99 引入的固定大小整数类型,不随编译器和机器变化,是精确控制数据大小的最佳途径 🔵 核心
sizeof(T) sizeof 返回存储类型 T 所需字节数,用来写可移植代码 ⚫ 事实
可移植性 portability 使程序对不同数据类型的确切大小不敏感 🔵 核心

2.1.3 寻址和字节顺序

术语 英文 解释 标注
小端法 little endian 最低有效字节存放在最低地址;Intel x86/x86-64、ARM(Android/iOS) 使用 🔵 核心
大端法 big endian 最高有效字节存放在最低地址;IBM 大型机、旧 Sun SPARC 使用 🔵 核心
双端法 bi-endian 硬件两种模式都支持,但 OS 选定后固定;某些 ARM 芯片有此特性 ⚫ 事实
最低有效字节 least significant byte 权重最小的字节,对数值影响最小 ⚫ 事实
最高有效字节 most significant byte 权重最大的字节,对数值影响最大 ⚫ 事实
强制类型转换 cast (byte_pointer) &x --- 把指向任意类型的指针强转为字节指针,从而查看原始字节 🔵 核心
网络字节序 network byte order 网络传输时的统一字节顺序标准,发送方和接收方各自转换 🟢 绿(第 11 章)
反汇编器 disassembler 将机器代码字节序列还原为汇编指令的工具 🟢 绿(第 3 章)
byte_pointer byte_pointer typedef unsigned char *byte_pointer; --- 指向单个字节的指针类型 ⚫ 事实

2.1.4 表示字符串

术语 英文 解释 标注
ASCII American Standard Code for Information Interchange 最常见字符编码标准,每个字符 1 字节;数字 'x' 的 ASCII 码 = 0x3x ⚫ 事实
null 终止符 null terminator C 字符串末尾的值为 0 的字节(\0),标志字符串结束 ⚫ 事实
Unicode Unicode 涵盖近 10 万字符的编码标准,支持多语言 ⚫ 事实
UTF-8 UTF-8 Unicode 的变长编码,ASCII 字符保持单字节兼容 ⚫ 事实

2.1.5 表示代码

术语 英文 解释 标注
机器代码 machine code 程序编译后的二进制指令字节序列,不同平台(CPU/OS)完全不兼容 🔵 核心
指令集 instruction set 处理器支持的指令及其编码方式的集合,不同 CPU 完全不同 🟢 绿(第 3、4 章)

2.1.6 布尔代数简介

术语 英文 解释 标注
布尔代数 Boolean algebra 研究 0 和 1 运算的数学体系,由 George Boole 于 1850 年代创立 ⚫ 事实
位向量 bit vector 固定长度 w 的 0/1 序列;布尔运算逐位进行 ⚫ 事实
NOT(非) NOT ~ --- 每位取反:1→0,0→1 ⚫ 事实
AND(与) AND & --- 两位都为 1 结果才为 1 ⚫ 事实
OR(或) OR ` ` --- 至少一位为 1 结果即为 1
XOR(异或) XOR ^ --- 两位不同结果才为 1;关键性质:a ^ a = 0 ⚫ 事实

2.1.7 C 语言中的位级运算

术语 英文 解释 标注
位级运算(按位运算) bit-level operation 对整型数据的每个 bit 独立进行布尔运算 ⚫ 事实
掩码 mask 位模式,用来选取或修改一个字中的指定位;x & 0xFF 提取低字节 🔵 核心
~0 ~0 生成全 1 掩码的可移植写法,自动适配字长;优于硬编码 0xFFFFFFFF 🔵 核心

2.1.8 C 语言中的逻辑运算

术语 英文 解释 标注
逻辑运算 logical operation &&、`
短路求值 short-circuit evaluation && / `

2.1.9 C 语言中的移位运算

术语 英文 解释 标注
左移 left shift (<<) 向左移 k 位,丢弃高位,右边补 k 个 0;等价于 x × 2 k x \times 2^k x×2k ⚫ 事实
逻辑右移 logical right shift 向右移 k 位,左边补 0;无符号数专用 ⚫ 事实
算术右移 arithmetic right shift 向右移 k 位,左边补符号位(MSB 是啥补啥);有符号数常用,保持正负号 🔵 核心
移位量未定义行为 undefined shift amount 移位量 ≥ 字长时,C 标准不规定行为;实际多数机器取 k mod w 🔴 红色
移位优先级陷阱 shift precedence pitfall 加减法优先级 > 移位运算符,1<<2+3<<4(1<<2)+(3<<4) 🔴 红色
相关推荐
一勺菠萝丶1 小时前
Linux 服务器临时用户创建与删除教程
linux·运维·服务器
lunzi_08261 小时前
《图解HTTP》--第5章-与HTTP协作的Web服务器
服务器·前端·http
imDwAaY1 小时前
机器学习入门:从感知机到逻辑回归,理解线性分类器与Softmax CS188 Note20 学习笔记
人工智能·笔记·python·学习·机器学习·逻辑回归
chushiyunen1 小时前
json-rpc笔记
笔记·rpc·json
酿情师2 小时前
当矿池掌握 51% 算力后,会发生什么?
网络·区块链·挖矿·矿池
诸葛思颖2 小时前
论文阅读笔记——NetLLM :当LLM遇上网络管理
论文阅读·笔记
2401_868534782 小时前
防火墙的具体概念
服务器·网络·php
驭渊的小故事2 小时前
网络初始1(2000字详细剖析网络的TCP/IP协议栈)
linux·服务器·网络
NULL指向我2 小时前
TMS320F28379D笔记3:CPU定时器+SCi串口通信+micro_print
笔记