深入理解计算机系统(笔记):信息的表示和处理

来源:互联网 发布:有趣的程序员密码 编辑:程序博客网 时间:2024/04/28 21:32


1. 信息存储

    程序将存储器视为一个字节数组,叫做虚拟存储器(virtual memory),数组中每个字节都有一个数字来标识,这个数字就是地址(address),所有可能的地址的集合叫做虚拟地址空间(virtual address space)。虚拟地址空间是给程序提供的概念性映像,实际的实现是将RAM、硬盘、特殊硬件和OS软件结合起来。

    编译器和运行时系统通过各种机制来分配和管理程序不同部分的存储,比如程序数据、指令、控制信息等。

1.1 十六进制表示法

0 - F

1.2 字(Word)

每台计算机都有一个字长,表明整数和指针类型的标称大小(nominal size)。由于虚拟地址以一个字来编码,所以字长可以决定虚拟地址空间的最大大小。字长为n位的机器,虚拟地址范围为0 - 2^(n-1)。现今计算机大多数为32和64位。

1.3 数据类型大小

指针大小为机器字长。数据类型在不同机器/编译器上的大小不同会引起可移植性问题。

实际上C语言只规定了每种类型的最小长度,而实际长度根据机器不同可能不同。


1.4 寻址和字节顺序

占多个字节的对象,解析它需要确定两个方面:对象地址,字节在存储器中如何排列

一般情况下,对象地址使用字节序列的最小地址

字节顺序有两种规则:小端法(little endian),大端法(big endian)

小端法就是低地址(地址值越大)对应高位,大端法就是高地址(地址值越小)对应高位

如下所示,变量x地址为0x100,十六进制值为0x01234567,地址范围是0x100 - 0x103,,大端和小端表示法分别如下:


以下是不同机器上的字节表示,可以看到Sun用的是大端法,其他用的小端法


1.5 二进制移位运算

左移运算:向左移动n位,丢弃最高n位,右端补n个0

右移分为逻辑右移和算术右移

逻辑右移:不管数据的符号位,将数据当成一个纯粹的bit串来移位,左边补0

算术右移:左边补符号位(符号位本身也参与移位)


2. 整数表示

2.1 补码编码表示负数

补码是按位取反再加1,计算机中数据的补码编码是符号位(最高位)+剩余位的补码表示,符号位1表示负数,0表示正数。可以通过如下方式计算


补码编码的取值范围为TMin - TMax,则|TMin| = |TMax| + 1


2.2 无符号数与有符号数转换

大多数C语言的实现都是不改变位模式(就是二进制值不变),只改变解释数据的方式,比如:

short int v = -12345;

unsigned short uv = (unsigned short) v;

打印出后,v = -12345(1100111111000111), uv = 53191(1100111111000111)


2.3 扩展数字的位表示

short sx = -12345;

unsigned short usx = sx;

int x = sx;

unsigned ux = usx;

打印出来分别为

sx    = -12345  : cf c7

usx  = 53191   : cf c7

x       = -12345 : ff ff cf c7

ux    = 53191   : 00 00 cf c7

在16位字长类型时,该数据的二进制表示相同,但是32位类型时却不同了。


short sx = -12345;

unsigned uy = sx;

打印出uy的值为:

uy = 4294954951 : ff ff cf c7

这表明将short转换成unsigned int时,我们先改变了大小,再转换成了无符号类型。也就是说(unsigned)sx 等价于 (unsigned)(int) sx。


2.4 整数运算

如何判断两个unsigned int的和是否溢出?

unsigned int a = 23;

unsigned int b = 87;

unsigned int x = a + b;

如果x < a(或者x < b)则发生了溢出。


有符号数的运算在底层实际上执行和无符号数完全相同的指令,不过有符号数可能正溢出,也可能负溢出,当a、b都小于0,但他们的和大于0时发生负溢出,当a、b都大于0,但和小于0时发生正溢出。



整数乘法耗费很多CPU周期,相比来说移位和加减法只需要一个周期,因此可以使用移位和加减法来代替乘法运算:

表达式S * 14可以写成S * (8 + 4 + 2) = S * (2^3 + 2^2 + 2^1),这样就可以通过3个左移运算和两个加法运算代替乘法运算,即使该表达式会产生溢出转换的结果也相同(同样会产生溢出)。进一步,这个表达式还可以写成S * (2^4 - 2^1),只要两个左移和一个减法。

除法就没这么幸运了,除法只能在被除数为2的幂次方的情况下用右移代替,其他情况不行。


3. 浮点数

浮点数二进制表示:101.11表示1*2^2 + 0*2^1 + 1*2^0 + 1*2^-1 + 1*2^-2 = 5 3/4(5.75)

由于小数表示的特定,浮点数小数部分不能精确表示某些值,比如1/5,十进制可以用0.2精确表示,但是二进制就只能用一个近似值表示



3.1 IEEE浮点数表示

使用(-1)^s * M * 2^E 的形式表示一个数:

符号(sign)s决定该数的正负

尾数(significant)M是一个二进制小数

阶码(exponent)E对浮点数加权,权重是2的E次幂(可能是负数次幂)


一个二进制数被划分成3个字段来表示上诉形式:

单独的符号位s,编码符号s

k位的阶码字段exp,编码阶码E

n位小数字段frac,编码尾数M,编码出的值依赖于阶码字段的值是否为0



根据exp的值,浮点数值可分成3中不同情况:


阶码字段被解释为以偏置(biased)形式表示的有符号整数,阶码的值是E = e - Bias,其中e是无符号数就是阶码字段的值(对于非规格化数来说,e = 1,那么非规格化的E = 1 - Bias),Bias = 2^(k - 1) - 1(单精度为2^8 - 1 = 127, 双精度为2^10 - 1 = 1023)。假设小数部分的整数值为v,位数为n,则小数部分的值为f = v/(2^n),这就是非规格化数的小数部分实际值M = f,而规格化数需要加上1,则规格化数小数部分值为M = 1 + f(非规格化小数部分值M = f)。最终表示的浮点数绝对值为V = 2^E + M。实例如下:


浮点数加法不具有结合性


缩写和概念:

ASCII:American Standard Code for Information Interchange,美国信息交换标准码

Unicode标准:ASCII只适合英语编码,无法满足特殊字符多的语言编码要求,如中文、希腊文等。Unicode就是用来表示更多语言编码的“统一字符集”,使用32位表示字符。

IEEE: Institute of Electrical and Electronic Engineers,电气与电子工程师协会,读作"Eye Triple-Eee"

0 0