第02章:信息的表示与处理
0、二进制与计算机信息
现代计算机存储和处理信息,是以二进制信号来表示的。这些二进制数字,即是“位 bit”,形成了数字革命的基础。
1)计算机为什么要选择二进制来表示信息呢?
因为二进制信息能够很容易地被表示、存储和传输。二值信号进行存储和执行计算的电子电路非常简单可靠,一个硅片上可以集成数十亿个这样的电路。
2)学习三种数字(无符号数字、有符号数字、浮点数字)的表示方式
计算机用几种不同的二进制表示形式来编码数值,并通过直接操作数字的位级表示,得到几种算术运算方式。理解这些技术,对于理解编译器产生的机器级代码是非常重要的,编译器会试图优化算术表达式求值的性能。
3)为什么会发生“溢出”?
4)关于浮点运算与精度问题
5)为什么要学习数字的二进制表示?
通过研究数字的二进制表示,我们可以进一步学习表示值的范围,以及不同算术运算的属性。大量计算机的安全漏洞都是由于计算机算术运算的微妙细节引发的。
6)关于 C 编程语言的演变
1、信息存储
1)关于虚拟地址空间
大多数的计算机,都使用 8位的“块”或“字节”作为内存的最小地址单元。机器级程序把内存看作是一个非常大的字节数组,即虚拟内存。
内存的每个字节都由一个唯一的数字来表示,即地址。所有可能的地址的集合,即虚拟地址空间。这个虚拟地址空间只是一个展现给机器级程序的抽象概念。实际上的实现,是把动态随机访问存储器(DRAM)、闪存、磁盘存储器、特殊硬件和操作系统软件结合起来,为程序提供一个看上去统一的字节数组。
在接下来的章节中,我们将讲述编程器和运行时系统是如何把存储器空间划分成更加可管理的单元,以存放不同的程序对象(程序数据、指令或控制信息)。这种管理完全是在虚拟地址空间里完成的。
每个程序对象都可以简单地被看成是一个字节块,而程序本身是一个字节序列。
2)关于 C 语言中指针的作用
3)非常重要的有用的 十六进制(2的四次方)
4)十六进制和二进制数据之间的相互转换
5)什么是字长(word size)?它影响着什么?
字长决定着虚拟地址空间的大小。字长为32位的机器,其虚拟地址空间为4GB;字长为64位的机器,其虚拟地址空间为16EB。
大多数64位的机器也可以运行32位机器编译的程序,这是一种向后兼容。
计算机和编译器支持多种不同方式编码的数字格式。许多机器都有处理单个字节的指令,也有处理2字节、4字节或8字节的指令。C语言的数据类型,在32位程序和64位程序下的字节数对比如下图示:
6)寻址和字节顺序
最低有效字节在最前面的方式,称为小端法;最高有效字节在最前面的方式,称为大端法。
大多数的Intel兼容机都只用小端模式。事实上,一旦选择了特定操作系统,那么字节顺序也就固定下来了。
7)表示字符串
Java编程语言使用 Unicode 来表示字符串。对于 C语言也支持 Unicode 的程序库。
8)表示代码
计算机系统的一个基本概念就是,从机器的角度来看,程序仅仅只是字节序列。机器没有关于原始源程序的任何信息,除了可能有些用来帮助调试的辅助表示以外。
2、布尔代数简介
最简单的布尔代数是在二元集合 {0, 1} 的基础上的定义。
3、C语言中的位级运算
4、C语言中的逻辑运算
5、C语言中的移位运算
C语言还提供了一组移位运算,向左或者向右移动位模式。
2、整数的表示
1)常用的符号术语
2)C语言支持多种整型数据类型,它表示有限范围的整数。如下图,给出了 32位机器和64位机器上的取值范围。
3)把二进制转化为无符号的十进制数
无符号数的编码具有唯一性,即唯一的无符号数对应唯一的二进制编码,且是一一对应的。
4)补码编码
补码编码也具有唯一性,即唯一的有符号整数,对应着唯一的二进制编程,且是一一对应的。
5)有 w 位的二进制编码,所对应的有符号数、无符号数的最大值和最小值分别是多少?
对于某些程序来讲,用确定大小的表示来编码数据类型,是非常重要的。当编写程序时,使得机器能够按照一个标准协议在因特网上通信,让数据类型与协议指定的数据类型兼容是非常有必要的。
在Java中,关于数据类型的取值范围和表示,是非常明确的,Java标准统一要求采用补码编码来表示。
6)关于反码编码和原码编码
7)关于反汇编器(反编译)
反汇编器是一种将可执行目标程序文件转换回可读性更好的ASCII码形式的程序工具,即反编译工具。
8)有符号数与无符号数之间的相互转换
C语言允许数据类型之间的强制类型转换。强制类型转换的结果保持位值不变,只是改变了解释这些位的方式,即“数值可能会改变,但是位模式不变”。
unsigned u = 4294967295u;
int tu = (int) u;
printf("u = %u, tu=%d\n", u, tu);
// 得到的结果是 tu=-1
9)C语言中的有符号数和无符号数
10)C语言中的隐式类型转换
由于C同时支持有符号数和无符号数的运算,所以就会出现这种隐式类型转换。当执行一个运算时,如果它的一个运算数是有符号的,而另一个是无符号数,那么C语言会根据隐式类型转换规则把有符号数转换成无符号数,并假设这两个数都是非负的。
11)扩展一个数字的位表示(位扩展)
12)截断一个数字的位表示(位截断)
13)关于有符号数和无符号数的建议
3、整数运行
1)开篇疑问
2)无符号数的加法
3)无符号数求反
4)有符号数的加法
5)有符号数的非
6)无符号数的乘法
7)有符号数的乘法
8)用移位运算和加法运算来优化乘法运算
注:无论是无符号数,还是有符号数,乘以2的幂,都可能导致溢出。但结果表明,使用移位运算优化后的乘法运算,与未优化的乘法运算,得到的结果是一致的。
9)使用移位运算优化除法运算
在大多数机器上,整数除法比整数乘法更慢,除法需要30个或者更多的时钟周期。除以2的幂,也可以使用移位运算(右移)来实现。
10)关于整数运算的最后思考
4、浮点数
1)关于浮点数
本小节,我们将看到 IEEE 浮点格式中数字是如何表示的。还将深入探讨“舍入”的问题,即当一个数字不能被准确地表示为这种格式时,就必须向上调整或者向下调整。
2)关于 IEEE
3)浮点数的二进制表示法(类比浮点数的十进制表示法)
4)IEEE 浮点数的表示法
5)舍入
6)关于浮点运算
7)C语言中的浮点数
5、本章小结
在使用浮点运算时必须非常小心,因为浮点运算只有有限的范围和精度,而且不遵守普遍的算术属性,比如结合性。
END 2019-02-01