avatar

朝花惜拾

Be a Real Engineer

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于
Home CSAPP Ch2. 信息的表示和处理
文章

CSAPP Ch2. 信息的表示和处理

Posted 2024-04-16 Updated 2025-04- 22
By Ray Lyu
17~22 min read

信息存储

任何信息在计算机中都是由 0 和 1 组成的比特串,但程序一般都是按字节进行寻址,而不会访问单独的比特位。对于程序来说,内存就是一个巨大的字节数组。字长是计算机地址(指针值)的占位大小,对于一台 w 位的机器,其虚拟地址空间的最大范围就是[0, 2^{w}-1]。

硬件和操作系统共同决定了信息在内存中存储的字节顺序,分大端法和小端法两种。“大端”就是数值高位在前,“小端”就是数值低位在前。比如,对于十六进制数 0x01234567(32位,4字节),大端法存储就01、23、45、67,小端法存储就是67、45、23、01。在 Linux 中执行 lscpu 命令可以看到系统的字节顺序,也可以通过下面的 C 程序进行判断。

#include <stdio.h>

void show_bytes(void *ptr, int len) {
    for (int i = 0; i < len; i++) {
        printf("%.2x ", ((unsigned char *)ptr)[i]);
    }
    printf("\n");
}

int main() {
    int num = 0x01234567;
    show_bytes(&num, sizeof(int)); // 小端存储输出结果为:67 45 23 01
}

整数

最早的时候,人们发明计算机仅仅是为了数学计算 [2]。因此,必然要了解数在计算机中的表示与运算。浮点数的表示机制比较复杂,我们着重了解整数部分。

整数表示

无符号整数容易理解,它基本就是原生的二进制表示。但无符号整数的使用场景很有限,事实上,除了 C 以外很少有语言支持无符号整数(语言的设计者认为其带来的弊大于利)。有符号数有三种标准的表示方法:原码、反码和补码,现在几乎所有的机器都以补码来表示有符号整数和实现运算。

补码表示

对于w位的比特串 x_{w-1}x_{w-2}...x_1x_0,它表示的数值为:

-x_{w-1}*2^{w-1}+\sum_{i=0}^{w-2} x_i2^{i}

w位补码编码表示的范围是-2^{w-1}到2^{w-1}-1。

整数运算

补码加法

记+为一般的整数加法,定义+^t_w为补码加法,它使得x+^t_wy为整数和x+y的补码表示截断为w位的结果。关于补码加法有下面定理成立(证明略):

csapp ch2 补码加法定理.png

这其中最关键的是中间未溢出的部分,它保证了补码加法的正确性。我们通过下面表格来理解上述定理。

x

y

x+y

x+_wy

情况

-8 [1000]

-5 [1011]

10011

0011 [3]

负溢出

-8 [1000]

-8 [1000]

10000

0000 [0]

负溢出

-8 [1000]

5 [0101]

1101

1101 [-3]

没有溢出

2 [0010]

5 [0101]

0111

0111 [7]

没有溢出

-2 [1110]

-4 [1100]

11010

1010 [-6]

没有溢出

5 [0101]

5 [0101]

1010

1010 [-6]

正溢出

关于补码表示有一条性质值得注意:对于任意的w位补码数a,其关于补码加法+_w^t的逆元(记为-a)都可以通过\sim a+1快速得到,即对a的每一位求补,然后对结果加 1。特殊地,-2^{w-1}的逆元是它自己。

乘法与除法

在大多数机器上,整数的乘法指令相当慢,需要 10 个或者更多的时钟周期。整数除法则要更慢,需要 30 个或者更多的时钟周期,因此,编译器对于一些特殊的整数乘法和除法,会尝试使用诸如移位、加法等更初级的运算来进行代替,从而加快运算速度。

浮点数

浮点数的机器表示要复杂得多,因为原生的二进制小数表示体系无法基于少量的位来表示大规模的实数集合。这里只记录 IEEE 浮点标准中浮点数及其运算的一些重要特征,目前的计算机实际上都支持 IEEE 浮点标准。

  • 浮点数天然无法精确表示所有实数,对于绝大部分实数只能进行近似表示;

  • 可表示的实数并不是均匀分布的,越靠近原点处越稠密;

csapp ch2 浮点数分布.png

  • 浮点运算会取近似,同样也可能溢出,且浮点运算并不满足结合律和分配率,这些对于科学计算程序和编译器(以及任何对计算精度要求高的场景)的编写者来说很重要。

References

1. 《深入理解计算机系统》

2. 《穿越计算机的迷雾》

计算机系统基础
License:  CC BY 4.0
Share

Further Reading

Nov 26, 2024

TLPI:文件系统

1. 基本原理 磁盘可以被划分成互不重叠的分区,每个分区可以容纳任何类型的信息,但通常只会包含以下其一。 文件系统(FS):存放常规文件 数据区域:可作为裸设备访问,一些 DBMS 会使用该技术 交换区域:用于内核的内存管理 下面我们介绍文件系统。Linux 支持种类繁多的文件系统,包括 Windo

Oct 22, 2024

TLPI:动态内存分配

堆内存 动态内存分配是一种很常见的行为,因为很多数据结构的大小只有当程序跑起来之后才能确定,此时我们一般从堆(heap)中申请(事实上也可以从栈上申请,但这里不谈)。堆是一段长度可变的连续虚拟内存,始于进程的“未初始化数据段末尾”,随着内存的分配和释放而增减。堆的末端称为“program break

Sep 5, 2024

TLPI:文件 I/O

1. 文件描述符原理 所有执行 I/O 操作的系统调用都以文件描述符(一个非负整数)来指代打开的文件,文件描述符用以表示所有类型的已打开文件,包括管道、FIFO、socket、终端设备和普通文件。 inode:系统级,不考虑硬链接时,它与文件数据一一对应 打开文件句柄(open file handl

OLDER

Kube-scheduler 源码分析之调度队列

NEWER

Client-go 源码分析之 Informer 机制

Recently Updated

  • 6.824 Lab1: MapReduce
  • 服务架构演进小结
  • ChineseChess 程序:Minimax 算法与 Alpha-Beta 剪枝
  • 2024年终总结
  • 初识 RPC 与 REST

Trending Tags

算法 架构 分布式系统 Golang Linux 系统编程 Kubernetes 搜索

Contents

©2025 朝花惜拾. Some rights reserved.

Using the Halo theme Chirpy