计算机存储和处理信息以二值信号表示,称为位 bit
,是计算机中最小的数据单位,每一位的值只能是 0
或 1
。
单个的位不是非常有用。但将位组合在一起,再加上某种解释,即赋予不同的可能位模式以含义,就能够表示任何有限集合的元素,如 8 个位组成的字节。
字节 byte
也称块,是由 8 位二进制数组成,作为最小的可寻址的 内存单位,而不是访问内存中单独的位。
机器级程序将内存视为一个非常大的字节数组,称为虚拟内存 virtual memory
。内存的每个字节都由一个唯一的数字来标识,称为它的地址 address
,所有可能地址的集合就称为虚拟地址空间 virtual address space
。
虚拟地址空间最大大小取决于计算机的字长 word size
。字长指明指针数据的标称大小 nominal size
。对于一个字长为 w 位的机器而言,虚拟地址的范围 ,程序最多访问 个字节。
进位计数法
进位计数法是一种计数的方法。常用的进位计数法有十进制、二进制、十六进制、八进制等。十进制是人们在日常生活中最常使用的,而在计算机中通常使用二进制数、八进制数和十六进制数。
在进位计数法中,每个数位所用到的不同数码的个数称为 基数。每个数码所表示的数值等于该数码本身乘以一个与它所在数位有关的常数,这个常数称为 位权。一个进位数的数值大小就是它的各位数码按权相加。
一个 r 进制数 的数值可表示为
式中,r 是基数; 是第 i 位的位权; 的取值可以是 0,1,···,r-1 共 r 个数码中的任意一个。整数位最低位规定为第0位。
二进制
二进制 Binary
由 0
和 1
组成,基数为 2
,每个数位计满 2
就向高位进位,即逢二进一
。它的任意数位的权为 ,i
为所在位数。
对于一个既包含整数部分,又包含小数部分的二进制数字 1111000010.01101
,在转换时以小数点为界,往左是整数部分,往右是小数部分,八进制以 3 位一组,十六进制以 4 位一组,不足部分加 0
补齐。
高位补0,凑足三位 分界点 低位补0,凑足三位
001 111 000 010 . 011 010
——- ——- ——- ——- ——- ——-
转换为八进制后为 。
高位补0,凑足四位 分界点 低位补0,凑足四位
0011 1100 0010 . 0110 1000
———— ———— ———— ———— ————
转换为十六进制后为 。
八进制
八进制 Octal
由 0~7
组成,基数为 8
,每个数位计满 8
就向高位进位,即逢八进一
。因为 ,故 3 位二进制数码与 1 位八进制数码相对应。
将八进制转换成二进制,只需将每位改为 3 位二进制数即可,必要时去掉整数最高位或小数最低位的 0
;八进制转换为十六进制时,需先转换为二进制,然后由二进制数转换为十六进制。
十进制
十进制 decimal
由 0~9
组成,基数为 10
,每个数位计满 10
就向高位进位,即 逢十进一
。
对于其他进制数要转换为十进制,需要将进制的各位数码与它们的权值相乘,再把乘积相加,就得到了一个十进制数。这种方法称为按权展开相加法,如下所示。
而对于一个十进制数转换为任意进制数,常采用基数乘除法,对十进制数的整数部分和小数部分分别处理。整数部分采用除基取余法,小数部分采用乘基取整法,然后将整数部分与小数部分所转换的结果拼接起来。以下对十进制数 123.6875
使用基数乘除法来转换为二进制数。
除基取余法 是将整数部分除基取余,最先取得的余数为数的最低位,最后取得的余数为数的最高位,即除基取余,先余为低,后余为高,商为 0
时结束。
整数部分: 除基 取余
2 | 1 2 3 1 最低位
|————————
2 | 6 1 1
|————————
2 | 3 0 0
|————————
2 | 1 5 1
|————————
2 | 7 1
|————————
2 | 3 1
|————————
2 | 1 1 最高位
|————————
0
故整数部分 。
乘基取整法 是将小数部分乘基取整,先取得的整数为数的最高位,最后取得的整数为数的最低位,即乘基取整,先整为高,后整为低,乘积为 0
时结束,或满足精度要求。
小数部分: 乘基 取整
0.6875
× 2
————————————
1.3750 1 最高位
0.3750
× 2
————————————
0.7500 0
× 2
————————————
1.5000 1
0.5000
× 2
————————————
1.0000 1 最低位
······
故小数部分 。
所以,将整数部分和小数部分拼接起来后的结果为 。
计算机中的小数和整数不一样,整数可以连续表示,但小数是离散的,所以并不是每个十进制小数都可以准确地用二进制表示。例如
0.3
,无论经过多少次乘二取整转换都无法得到精确的结果。但任意一个二进制小数都可以由十进制小数表示。
十六进制
十六进制 hexadecimal
简写为 hex
,由数字 0~9
以及字符 A~F
组成,字符也可小写为 a~f
,其基数为 16,每个数位计满 16
就像高位进位,即 逢十六进一
。因为 ,故 4 位二进制数码与 1 位十六进制数码相对应。下表展示了几种进制数对照关系。
| 十六进制 | 二进制 | 十进制 | 八进制 |
|---|---|---|---|
| 0 | 0000 | 0 | 0 |
| 1 | 0001 | 1 | 1 |
| 2 | 0010 | 2 | 2 |
| 3 | 0011 | 3 | 3 |
| 4 | 0100 | 4 | 4 |
| 5 | 0101 | 5 | 5 |
| 6 | 0110 | 6 | 6 |
| 7 | 0111 | 7 | 7 |
| 8 | 1000 | 8 | 10 |
| 9 | 1001 | 9 | 11 |
| A | 1010 | 10 | 12 |
| B | 1011 | 11 | 13 |
| C | 1100 | 12 | 14 |
| D | 1101 | 13 | 15 |
| E | 1110 | 14 | 16 |
| F | 1111 | 15 | 17 |
由十六进制转换成二进制数,只需将每位改为 4
位二进制数即可,必要时去掉整数最高位或小数最低位的 0
;十六进制转换为八进制时,需先转换为二进制,然后由二进制数转换为八进制。
数据大小
计算机和编译器支持多种不同方式编码的数字格式,如不同长度的整数和浮点数。由于计算机位数的不同,会造成计算机的各种数据类型的字节数不一样。下表展示了 C 语言各种数据类型在 32 位机器和 64 位机器上分配的字节数。
| C声明 | 字节数 | ||
|---|---|---|---|
| 有符号 | 无符号 | 32位 | 64位 |
| [signed] char | unsigned char | 1 | 1 |
| short | unsigned short | 2 | 2 |
| int | unsigned | 4 | 4 |
| long | unsigned long | 4 | 8 |
| int32_t | uint32_t | 4 | 4 |
| int64_t | uint64_t | 8 | 8 |
| char * | 4 | 8 | |
| float | 4 | 4 | |
| double | 8 | 8 |
大部分数据类型都编码为有符号数值,除非有前缀关键字 unsigned
或对确定大小的数据类型使用了特定的无符号声明。数据类型 char
是个例外。
寻址和字节顺序
对于跨越多字节的程序对象,在几乎所有的机器上都被存储为连续的字节序列,对象的地址为所使用字节中最小的地址。
多字节对象在存储器中有两个通用的排列规则,即小端法和大端法。
一个 w 位的整数,其位表示为 ,其中 是最高有效位,而 是最低有效位,假设 w 是 8 的倍数,这些位就能被分组成为字节,其中最高有效字节包含位 ,而最低有效字节包含位 ,其他字节包含中间的位。
小端法 little endian
。机器选择在内存中按照从最低有效字节到最高有效字节的顺序存储,即最低有效字节在最前面的方式。大端法 big endian
。机器选择在内存中按照从最高有效字节到最低有效字节的顺序,即最高有效字节在最前面的方式。
假设变量 x
的类型为 int
,位于地址 0x100
处,它的十六进制值为 0x01234567
。地址范围 0x100~0x103
的字节顺序依赖于机器的类型:

在字
0x01234567
中,高位字节的十六进制值为0x01
,而低位字节值为0x67
。
一般而言,机器所使用的字节顺序是不可见的。无论为哪种类型的机器所编译的程序都会得到同样的结果。但有些情况下,字节顺序会成为问题。
不同类型的机器之间通过网络传送二进制数据时,会产生小端法机器产生的数据被发送到大端法机器或者反过来,接收程序会发现,字里的字节成了反序的。为了避免这类问题,网络应用程序的代码编写必须遵守已建立的关于字节顺序的规则,以确保发送方机器将它的内存表示转换成网络标准,而接收方机器则将网络标准转换为它的内部表示。 当通过反汇编器得到可执行程序的指令序列或编写规避正常的类型系统的程序时,字节顺序很重要。
字符串表示
由于计算机内部只能识别和处理二进制代码,所以字符都必须按照某种编码来表示。而字符串是指连续的一串字符,通常方式下,它们占用主存中连续的多个字节,每个字节存储一个字符。
最常见的是 7 位二进制值表示的 ASCII
字符码,可表示数字 0~9
、大写字母 A~Z
、小写字母 a~z
及一定数量的专用符号,共 128
个字符。如字符 x
的 ASCII
码十进制为 120
,用二进制表示为 0111 1000
。在使用 ASCII
码作为字符码的任何系统上都将得到相同的结果,与字节顺序和字大小规则无关。因而,文本数据比二进制数据具有更强的平台独立性。
代码表示
从机器的角度看,程序仅仅只是字节序列。而不同的机器类型使用的是不同且不兼容的指令和编码方式,程序在不同机器中通过编译器翻译成对应机器的二进制序列也是不兼容的。二进制代码很少能在不同机器和操作系统组合之间移植。





