一、信息存储
大多数计算机使用8位的块,或者字节(byte),作为最小的可寻址的内存单位,而不是访问内存中单独的位。
机器级程序将内存视为一个非常大的字节数组,称为虚拟内存。
内存的每个字节都有一个唯一的数字来标识,称为它的地址,所有可能地址的集合就称为虚拟地址空间。
- 十六进制表示法
在C语言中,以0x或0X开头的数字常量被认为是十六进制的值。
十进制和十六进制表示之间的转换需要使用乘法或者除法来处理一般情况。 - 字数据大小
每台计算机都有一个字长,指明指针数据的标称大小。
因为虚拟地址是以这样的一个字来编码的,所以字长决定的最重要的系统参数就是虚拟地址空间的最大大小。 - 寻址和字节顺序
在几乎所有的机器上,多字节对象都被存储为连续的字节序列,对象的地址为所使用字节中最小的地址。
某些机器选择在内存中按照从最低有效字节到最高有效字节的顺序存储对象,而另一些机器则相反。
前一种规则–最低有效字节在最前面的方式,称为小端法。
后一种规则–最高有效字节在最前面的方式,称为大端法。 - 表示字符串
C语言中字符串被编码为一个以null(其值为0)字符结尾的字符数组。
每个字符都由某个标准编码来表示,最常见的是ASCII字符码。 - 布尔代数简介
最简单的布尔代数是在二元集合{0,1}基础上的定义。图2-7定义了这种布尔代数中的几种运算。
我们可以将上述4个布尔运算扩展到位向量的运算,位向量就是固定长度为w、由0和1组成的串。
位向量的运算可以定义成参数的每个对应元素之间的运算。 - C语言中的位级运算
C语言的一个很有用的特性就是它支持按位布尔运算。
|就是OR(或),&就是AND(与),~就是NOT(取反),而^就是EXCLUSIVE-OR(异或)。
位级运算的一个常见用法就是实现掩码运算,这里掩码是一个位模式,表示从一个字中选出的位的集合。 - C语言中的逻辑运算
C语言还提供了一组逻辑运算符||、&&、和!,分别对应于命题逻辑中的OR、AND和NOT运算。
逻辑运算认为所有非零的参数都表示TRUE,而参数0表示FALSE。
如果对第一个参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。 - C语言中的移位运算
C语言还提供了一组移位运算,向左或者向右移动位模式。
C表达式x<<k表示x向左移动k位,丢弃最高的k位,并在右端补k个0。
一般来说,机器支持两种形式的右移:逻辑右移和算术右移。
逻辑右移在左端补k个0,算术右移在左端补k个最高有效位的值。
二、整数表示
- 整数数据类型
C语言支持多种整数数据类型–表示有限范围的整数。
这些类型如图2-9和图2-10所示,其中还给出了32位和64位机器的取值范围。 - 无符号数的编码
假如有一个整数数据类型有w位。把x看作一个二进制表示的数,就获得了X的无符号表示。
在这个编码中,每个位Xi都取值为0或1,后一种取值意味着数值2的i次方应为数字值的一部分。 - 补码编码
对于许多应用,我们还希望表示负数值。最常见的有符号数的计算机表示方式就是补码形式。
在这个定义中,将字的最高有效位解释为负权。 - 有符号数和无符号数之间的转换
强制类型转换的结果保持位值不变,只是改变了解释这些位的方式。 - C语言中的有符号数与无符号数
C语言支持所有整形数据类型的有符号和无符号运算。通常,大多数数字都默认为是有符号的。
要创建一个无符号常量,必须加上后缀字符U或者u。
当一种类型的表达式被赋值给另外一种类型的变量时,转换是隐式发生的。
当执行一个运算时,如果他的一个运算数是有符号的而另一个是无符号的,
那么C语言会隐式地将有符号参数强制类型转换为无符号数,来执行这个运算。 - 扩展一个数字的位表示
要将一个无符号数转换为一个更大的数据类型,只要简单地在表示的开头添加0,这种运算被称为零扩展。
要将一个补码数字转换为一个更大的数据类型,可以执行一个符号扩展,在表示中添加最高有效位的值。
值得一提的是,从一个数据大小到另一个数据大小的转换,以及无符号和有符号数字之间的转换的相对顺序能够影响一个程序的行为。 - 截断数字
当将一个w位的输截断为一个k位数字时,我们会丢弃高w-k位,得到一个新数字。
截断一个数字可能会改变它的值–溢出的一种形式。
三、整数运算
- 无符号加法
算数运算溢出,是指完整的整数结果不能放到数据类型的字长限制中去。
当执行C程序时,不会将溢出作为错误而发信号。 - 补码加法
两个数的补码之和与无符号之和有完全相同的位级表示。 - 补码的非
- 无符号乘法
- 补码乘法
对于无符号和补码乘法来说,乘法运算的位级表示都是一样的。 - 乘以常数
左移一个数值等价于执行一个与2的幂相乘的无符号乘法。
由于整数乘法比移位和加法的代价要大得多,许多C语言编译器试图以移位、加法和减法的组合来消除许多整数乘以常数的情况。 - 除以2的幂
四、浮点数
浮点表示对有理数进行编码。
他对执行涉及非常大的数字、非常接近于0的数字,以及更普遍的作为实数运算的近似值的计算,是很有用的。
- 二进制小数
对于一个二进制数,其中每个位的取值范围都是0和1,点左边的位的权是2的正幂,点右边的位的权是2的负幂。
这种表示方法表示的数为每个位的加权和。
小数的二进制表示法只能表示那些能够被写成x * 2y的数,其他的值只能够被近似的表示。 - IEEE浮点表示
IEEE浮点标准用符号、尾数和阶码来表示一个数。
将浮点数的位表示划分为三个字段,分别对这些值进行编码:
① 一个单独的符号位 s
② k位的阶码字段 E
③ n位小数字段 M
在单精度浮点格式(float)中,s、E和M分别为1位、8位和23位,得到一个32位的表示。
在双精度浮点格式(double)中,s、E和M分别为1位、11位和52位,得到一个64位的表示。
给定位表示,根据E的值,被编码的值可以分为三种不同的情况(最后一种情况有两种变种)。图2-33说明了对单精度格式的情况。 - 舍入
因为表示方法限制了浮点数的范围和精度,所以浮点运算只能近似的表示实数运算。
因此,对于一个值,我们一般想用一种系统的方法,能够找到最接近的值,他可以用期望的浮点形式表示出来。
这就是舍入运算的任务,关键问题是在两个可能值的中间确定舍入方向。 - 浮点运算
浮点加法运算是可交换的,但是不可结合的。另一方面,浮点加法满足了单调性属性。
浮点乘法运算是可交换的,但是不可结合的。另一方面,浮点乘法满足了单调性属性。
另外,浮点乘法在加法上不具备分配性。 - C语言中的浮点数
从int转换成float,数字不会溢出,但是可能被舍入。
从int或float转换成double,能够保留精确的数值。
从double转换成float,值可能溢出,也可能被舍入。
从float或double转换成int,值将会向零舍入。