深入理解计算机系统_第一部分 程序结构和执行_第2章 信息表示和处理

引言

  1. 我们研究三种重要的数字表示

1) 无符号编码

  • 基于传统二进制表示法
  • 表示大于或等于零的数字

2) 补码编码

  • 表示有符号整数
  • 有符号整数指的是可以为正或者为负的数字

3) 浮点数编码

  • 表示实数的科学记数法的以2为基数的版本
  1. 计算机编码的缺陷
  • 计算机编码用有限个“位”来表示一个数字编码
  • 结果太大不能被表示时或出现溢出
  1. 三种编码的特点

1) 整数的计算机具有乘法的结合律和交换律
2) 浮点运算

  • 溢出会产生 + ∞ +\infty +
  • 一组正数的乘积总是正的
  • 浮点运算不可结合(因为表示的精度有限)

3)整数运算和浮点运算的对比

  • 整数表示
    • 整数表示只能编码一个相对较小的数值范围
    • 这种表示是精确的
  • 浮点数
    • 可以编码一个较大的数值范围
    • 这种表示是近似的

2.1 信息存储

  1. 重要概念

1)字节:大多数计算机使用8位的块(字节),作为最小的可寻址的内存单位,而不是访问内存中单独的位。
2)虚拟内存:机器级程序将内存视作一个很大的字节数组,称作虚拟内存。
3) 地址:内存的每一个字节都有一个唯一的数字来标识,称为它的地址。
4)虚拟地址空间:所有可能的地址的集合称为虚拟地址空间。

  • 这个虚拟地址空间只是一个展示给机器级程序的概念性映像。
  • 实际的实现(见第9章)是将动态随机访问存储器(DRAM)、闪存、磁盘存储器、特殊硬件和操作系统软件结合起来,为应用程序提供一个看上去统一的字节数组。

5)程序对象:程序数据、指令和控制信息。

2.1.1 十六进制表示法

  1. 为什么选择十六进制

1)一个字节由8位组成,在二进制表示法中,它的值域是 0000000 0 2 ∼ 1111111 1 2 00000000_2\sim 11111111_2 000000002111111112,如果看成十进制就是 0 10 ∼ 25 5 10 0_{10}\sim 255_{10} 01025510.
2)两种表示法对于描述位模式都十分不方便。二进制表示法太冗长,十进制表示法与位模式的转化十分麻烦。

  1. 十六进制表示法

1)十六进制数

  • 十六进制使用0~9,以及字符A ~ F来表示16个可能的值,
  • 一个字节的值域为 0 0 16 ∼ F F 16 00_{16}\sim FF_{16} 0016FF16
  • 在C语言中,以0x或者0X开头的数字常量被认为是十六进制的数。字符‘A’ ~ ‘F’既可以是大写也可以是小写,例如我们可以将 F A 1 D 37 B 16 FA1D37B_{16} FA1D37B16写作 0 x F A 1 D 37 B 0xFA1D37B 0xFA1D37B,或者 0 x f a 1 d 37 b 0xfa1d37b 0xfa1d37b

2)十六进制和二进制之间的转换

  • 在这里插入图片描述
  • 注意:将二进制数字转化为十六进制的时候,要把二进制数字分割为每四个一组,如果总数不是四的倍数,最左边一组可以少于四位,前面用零补足。然后将每个四位组转化为相应的十六进制数字。
  • 当值x是2的幂时,也就是,对于某个n,x= 2 n 2^n 2n,我们可以很容易地将x写成十六进制形式。只要记住x的二进制表示就是1后面跟n个零。十六进制数字О代表四个二进制0。所以,对于被写成i+4j形式的n来说,其中0≤i≤3,我们可以把x写成开头的十六进制数字为1(i=0)、2(=1)、4 ( i=2)或者8(i=3),后面跟随着j个十六进制的0。比如,x=2048= 2 11 2^{11} 211,我们有n=11 =3+4·2,从而得到十六进制表示0x800。

3)十六进制和十进制之间的转换

  • 十进制和十六进制表示之间的转换需要使用乘法或者除法来处理一般情况。将一个十进制数字x转换为十六进制,我们可以反复地用16除x,得到一个商q和一个余数r,也就是x=q· 16+r。然后,我们用十六进制数字表示的r作为最低位数字,并且通过对q反复进行这个过程得到剩下的数字。例如,考虑十进制314156的转换:
    314156 = 19634 ⋅ 16 + 12 ( C ) 19634 = 1227 ⋅ 16 + 2 ( 2 ) 1227 = 76 ⋅ 16 + 11 ( B ) 76 = 4 ⋅ 16 + 12 ( C ) 4 = 0 ⋅ 16 + 4 ( 4 ) \begin{aligned} 314156 &=19634 \cdot 16+12 \qquad (C)\\ 19634 &=1227 \cdot 16+2 \qquad (2)\\ 1227 &=76 \cdot 16+11 \qquad (B)\\ 76 &=4 \cdot 16+12 \qquad (C)\\ 4 &=0 \cdot 16+4 \qquad (4) \end{aligned} 314156196341227764=1963416+12(C)=122716+2(2)=7616+11(B)=416+12(C)=016+4(4)
    从这里,我们能读出十六进制表示为0x4CB2C.
  • 反过来,将一个十六进制数字转换为十进制数字,我们可以用相应的16的幂乘以每个十六进制数字。比如,给定数字Ox7AF,我们计算它对应的十进制值为7*16+ 10*16+ 15=7*256+10*16+ 15= 1792+ 160+ 15= 1967。

2.1.2 字

  • 每台计算机都有一个字长( word size),指明整数和指针数据的标称大小( nominal size)。因为虚拟地址是以这样的字来编码的,所以字长决定的最重要的系统参数就是虚拟地址空间的最大大小。也就是说,对于一个字长为n位的机器而言,虚拟地址的范围为0~ 2 n 2^n 2n-1,程序最多访问 2 n 2^n 2n字节。

2.1.3 数据大小

  • 在这里插入图片描述

2.1.4 寻址和字节顺序

  1. 地址
  • 在几乎所有的机器上,多字节对象被存储为连续的字节序列,对象的地址为所使用的的字节序列的最小地址。
  • 例如,假设一个类型为int 的变量x的地址为0x100,也就是说,地址表达式&x的值为0x100。那么,x的四字节将被存储在存储器的0x100、0x101、0x102和0x103位置。
  1. 字节排序的两个通用规则:小端法&大端法
  • 对表示一个对象的字节序列排序,有两个通用的规则。考虑一个w位的整数,有位表示 [ x w − 1 , x w − 2 , ⋯   , x 1 , x 0 ] [\left.x_{w-1},x_{w-2}, \cdots, x_{1}, x_{0}\right] [xw1,xw2,,x1,x0],其中 x w − 1 x_{w-1} xw1最高有效位,而 x 0 x_{0} x0最低有效位。假设w是8的倍数,这些位就能被分组成为字节,其中最高有效字节包含位 [ x w − 1 , x w − 2 , ⋯   , x w − 8 ] \left[x_{w-1}, x_{w-2}, \cdots, x_{w-8}\right] [xw1,xw2,,xw8],而最低有效字节包含位 [ x 7 , x 6 , ⋯ x 0 ] \left[x_{7}, x_{6}, \cdots x_0\right] [x7,x6,x0],其他字节包含中间的位。某些机器选择在存储器中按照从最低有效字节到最高有效字节的顺序存储对象,而另一些机器则按照从最高有效字节到最低有效字节的顺序存储。前一种规则—–最低有效字节在最前面的方式被称为小端法(little endian)。大多数源自以前的Digital Equipment 公司(现在是Compaq公司的一部分)的机器,以及 Intel的机器都采用这种规则。后一种规则(最高有效字节在最前面的方式)被称为大端法(big endian)。IBM、Motorola和Sun Microsystems 的大多数机器都采用这种规则。注意我们说的是“大多数”。这些规则并没有严格按照企业界限来划分。比如,IBM制造的个人计算机使用的是Intel兼容的处理器,因此就是小端法。许多微处理器芯片,包括Alpha和Motorola的 PowerPC,能够运行在任一种模式中,其取决于芯片加电启动时确定的字节顺序规则。
  • 继续我们前面的示例,假设变量x类型为int,位于地址0x100 处,有一个十六进制值为0x01234567。地址范围0x100~0x103的字节顺序依赖于机器的类型:
    在这里插入图片描述
    注意,在字0x01234567中,高位字节的十六进制值为0x01,而低位字节值为0x67。
  1. 字节顺序变得重要的三种情况

1)小端法机器产生的数据被发送到大端法机器或者反之时,接收程序会发现,字里的字节变成了反序。为了避免这类问题,网络应用程序必须建立关于字节顺序的规则,以确保发送机器将它的内部表示转换为网络标准,而接收方机器则将网络标准转换为它的内部表示。
2)字节顺序变得重要的第二种情况是当阅读表示整数数据的字节序列时。这通常发生在检查机器级程序时。作为一个示例,从某个文件中摘出了下面这行代码,该文件给出了一个针对Intel 处理器的机器级代码的文本表示: 80483 b d : 01 05 64 94 04 08  add  % eax,  0 × 8049464 \begin{array}{llllllll} 80483 \mathrm{bd}: & 01 & 05 & 64 & 94 & 04 & 08 & \text { add } & \text {\% eax, } & 0 \times 8049464 \end{array} 80483bd:010564940408 add % eax, 0×8049464这一行是由反汇编器((disassembler)生成的,反汇编器是一种确定可执行程序文件所表示的指令序列的工具。我们将在下一章中学习有关这些工具的更多知识,以及怎样解释像这样的行。而现在,我们只是注意这行表述了十六进制字节串01 05 64 94 04 08是一条指令的字节级表示,这条指令是增加一个字宽的数据到存储在主存地址Ox8049464的值上。如果我们取出这个序列的最后四字节:64940408,并且按照相反的顺序写出,我们得到08049464。去掉开头的零,我们就得到值Ox8049464,就是右边写着的数值。当阅读像此例中一样的小端法机器生成的机器级程序表示时,经常会将字节按照相反的顺序显示。书写字节序列的自然方式是最低位字节在左边,而最高位字节在右边,但是这和书写数字时最高有效位在左边,最低有效位在右边的通常方式是相反的。
3)字节顺序变得重要的第三种情况是当编写规避正常的类型系统的程序时。在C语言中,可以通过使用强制类型转换或者联合来允许以一种数据类型来引用一个对象,而这种数据类型与创建这个对象时的定义的数据类型不同。

2.1.5 表示字符串

  • C语言中的字符串被编码成一个以null(其值为零)字符结尾的字符数组。每个字符都由某个标准编码来表示,最常见的是ASCII编码。
  • 在使用ASCII码作为字符码的任何系统上运行show_bytes程序,都将得到相同的结果,与字节顺序和字的大小规则无关。
    -因而文本数据比二进制数据具有更强的平台独立性。

2.1.6 表示代码

  • 指令编码是不同的。
    • 不同的机器类型使用不同的且不兼容的指令和编码类型。
    • 完全一样的进程,运行在不同的操作系统上也有不同的编码规则。因此二进制代码是不兼容的。

2.1.7 布尔代数简介

  1. 布尔代数:围绕数值0和1的数学知识体系。
  2. 0和1的运算
    在这里插入图片描述
  3. 位向量的运算:
    在这里插入图片描述
  • 用位向量表示有限集合:
    • a = [ 01101001 ] 可 以 表 示 A = { 0 , 3 , 5 , 6 } a=[01101001]可以表示A=\{0,3,5,6\} a=[01101001]A={ 0,3,5,6}
    • b = [ 01010101 ] 可 以 表 示 B = { 0 , 2 , 4 , 6 } b=[01010101]可以表示B=\{0,2,4,6\} b=[01010101]B={ 0,2,4,6}
    • 布尔运算 ∣ | & \& &分别对应于集合的并和交,而 ∼ \sim 对应于集合的补

2.1.8 C语言中的位级运算

  1. 示例
    在这里插入图片描述
  2. 掩码运算:
  • 例如: x = 0 x 89 A B C D E F 做 掩 码 运 算 x & 0 x F F = 0 x 000000 E F x=0x89ABCDEF做掩码运算x\& 0xFF=0x000000EF x=0x89ABCDEFx&0xFF=0x000000EF

2.1.9 C语言中的逻辑运算

  1. 逻辑运算容易与位级运算混淆,注意比较以下例子:
    在这里插入图片描述
  2. 位级运算与逻辑运算的区别:
  • 逻辑运算认为所有非零的参数都表示TRUE,参数零表示FALSE,返回值为1或者0.
  • 逻辑运算符如果对第一个参数求值就能确定表达式的值,那么逻辑运算符就不会对第二个参数求值。

2.1.10 C语言中的移位运算

  1. 示例在这里插入图片描述
  • 移位运算从左往右可结合
  • 右移运算包括逻辑右移算数右移

猜你喜欢

转载自blog.csdn.net/weixin_43567146/article/details/115293281