大多数计算机使用 8 位的块,或者宇节 (byte),作为最小的可寻址的内存单位,而不是访问内存中单独的位。机器级程序将内存视为一个非常大的字节数组,称为虚拟内存 (virtual memory)。内存的每个字节都由一个唯一的数字来标识,称为它的地址(address),所有可能地址的集合就称为虚拟地址空间 (virtual address space)。顾名思义,这个虚拟地址空间只是一个展现机器级程序的概念性映像。实际的实现(见第 9 章)是将动态随机访问存储器 DRAM 、闪存、磁盘存储器、特殊硬件和操作系统软件结合起来,为程序提供一个看上去统一的字节数组。
在接下来的几章中,我们将讲述编译器和运行时系统是如何将存储器空间划分为更可管理的单元,来存放不同的程序对象 (program object),即程序数据、指令和控制信息。可以用各种机制来分配和管理程序不同部分的存储。这种管理完全是在虚拟地址空间里完成的。例如,C 语言中一个指针的值(无论它指向一个整数、一个结构或是某个其他程序对象)都是某个存储块的第一个字节的虚拟地址。 C 编译器还把每个指针和类型信息联系起来,这样就可以根据指针值的类型,生成不同的机器级代码来访问存储在指针所指向位置处的值。尽管 C 编译器维护着这个类型信息,但是它生成的实际机器级程序并不包含关于数据类型的信息。每个程序对象可以简单地视为一个字节块,而程序本身就是一个字节序列。
一个字节由 8 位组成。在二进制表示法中,它的值域是 0000 0000 ~ 1111 1111。如果看成十进制整数,它的值域就是 0 ~255。两种符号表示法对于描述位模式来说都不是非常方便。二进制表示法太冗长,而十进制表示法与位模式的互相转化很麻烦。替代的方法是,以 16 为基数,或者叫做十六进制 (hexadecimal) 数,来表示位模式。十六进制(简写为 "hex")使用数字 '0'~'9' 以及字符 'A'~'F' 来表示 16 个可能的值。下图展示了 16 个十六进制数字对应的十进制值和二进制值。用十六进制书写,一个字节的值域为 00 ~FF。
| 十六进制数字 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| 十进制值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 二进制值 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 |
| 十六进制数字 | 8 | 9 | A | B | C | D | E | F |
|---|---|---|---|---|---|---|---|---|
| 十进制值 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 二进制值 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
在 C 语言中,以 Ox 或 OX 开头的数字常量被认为是十六进制的值。字符 'A'~'F' 既可以是大写,也可以是小写。例如,我们可以将数字 FA1D37B 写作 OxFA1D37B,或者 Oxfa1d37b,甚至是大小写混合,比如, OxFa1D37b 。在本书中,我们将使用 C 表示法来表示十六进制值。
编写机器级程序的一个常见任务就是在位模式的十进制、二进制和十六进制表示之间人工转换。二进制和十六进制之间的转换比较简单直接,因为可以一次执行一个十六进制数字的转换。数字的转换可以参考上图所示的表。一个简单的窍门是,记住十六进制数字 A、C 和 F 相应的十进制值。而对于把十六进制值 B、D 和 E 转换成十进制值,则可以通过计算它们与前三个值的相对关系来完成。
比如,假设给你一个数字 Ox173A4C。可以通过展开每个十六进制数字,将它转换为二进制格式,如下所示:
| 十六进制 | 1 | A | 3 | C |
|---|---|---|---|---|
| 二进制 | 0001 | 1010 | 0011 | 1100 |
这样就得到了二进制表示 0001101000111100。
反过来,如果如果给定一个二进制数字 0001101000111100,可以通过首先把它分为每 4 位一组来转换为十六进制。不过要注意,如果位总数不是 4 的倍数,最左边的一组可以少于 4 位,前面用 0 补足。然后将每个 4 位组转换为相应的十六进制数字。
| 十六进制 | 11 | 1100 | 1010 | 1101 |
|---|---|---|---|---|
| 二进制 | 3 | C | A | D |
当值 x 是 2 的非负整数 n 次幕时,也就是 , 我们可以很容易地将 x 写成十六进制形式,只要记住 x 的二进制表示就是 1 后面跟 n 个 0。十六进制数字 0 代表 4 个二进制 0。所以,当 n 表示成
的形式,其中 0≤i≤3, 我们可以把 x 写成开头的十六进制数字为 1(i=O)、2(i= 1)、4(i=2) 或者 8(i=3),后面跟随着 j 个十六进制的 0。比如,x=2048=
, 我们有 n=11=3+4*2,从而得到十六进制表示 Ox800。
十进制和十六进制表示之间的转换需要使用乘法或者除法来处理一般情况。将一个十进制数字 x 转换为十六进制,可以反复地用 16 除 x,得到一个商 q 和一个余数 r,也就是 x=q * 16 + r 。然后,我们用十六进制数字表示的 r 作为最低位数字,并且通过对 q 反复进行这个过程得到剩下的数字。例如,考虑十进制 314 156 的转换:
从这里,我们能读出十六进制表示为 Ox4CB2C。
反过来,将一个十六进制数字转换为十进制数字,我们可以用相应的 16 的幂乘以每个十六进制数字。比如,给定数字 Ox7AF,我们计算它对应的十进制值为







网友评论