计算机中发生的一切——你编写的代码、使用的数据、屏幕上的图像——都由一系列双态开关控制。开关的每种组合代表计算机可能处于的状态。如果你想描述计算机发生了什么,可以列出开关的组合。简单地说,这就像“第1个开关打开,第2个也打开,但是第3个关闭,而第4个打开。”但是这样描述计算机会很困难,特别是考虑到现代计算机使用了数十亿个开关。所以,我们将使用一种更简洁的数字符号。
你对十进制应该不陌生,这种进制使用0~9共计10个数码(digit)来书写数字(number)
。我们想要有一种用数字表示开关的方法,但是开关只有两个状态,而不是10个。在这里,二进制系统(一种使用0和1的两位数码系统)就要发挥作用了。
我们使用一个二进制数码(binary digit),通常简称为位(bit)
,来表示开关的状态。一个位有两个取值——0和1,前者表示开关的“关”(off),后者表示开关的“开”(on)。如果我们愿意,也可以给这些意义选择相反的值——重要的是保持一致。让我们用位来简化开关的描述。在先前的例子中,我们有一台计算机,其中第1个开关打开,第2个打开,第3个关闭,第4个打开。在二进制中,我们将其表示为1101。
即便采用了二进制,有时候位数还是太多,导致书写出的数字难以阅读。在这种情况下,我们使用十六进制数码(hexadecimal digit)来指定位模式(bit pattern)。十六进制系统的数码共有16种取值,分别表示某个4位组。
表2-1展示了4个位的16种组合以及每种组合对应的十六进制数码。使用一段时间之后,你应该就能记住这张表了,不过就算忘了也没关系,在网上可以搜到现成的“十六进制-二进制”转换器。
表2-1 4位二进制对应的十六进制表示
有了十六进制,我们就可以将1101,或者“开、开、关、开”写作单个十六进制数码:d 16 = 1101 2 。
如果上下文不够清晰,我会使用下标指明数字的基数。例如,100 10 表示十进制,100 16 表示十六进制,100 2 表示二进制。
八进制系统(基于8)不太常见,不过你偶尔也会遇到。八进制数码的取值为0~7,一个数码代表3位组。表2-2展示了每个可能的3位组及其对应的八进制数码。例如,如果想要简单地表示示例中的前3位,简单地写作6 8 即可,这相当于110 2 。
表2-2 3位二进制对应的八进制表示
当我们需要指定16或32个开关的状态时,十六进制数码尤为方便。可以将每个4位组写作1个十六进制数码。来看两个例子:
6c2a 16 = 0110110000101010 2
和
0123abcd 16 = 00000001001000111010101111001101 2
单个位对于数据存储通常没什么用处。计算机一次可以访问的最小位数被定义为字节(byte)。在大多数现代计算机中,一字节由8位组成,不过也有例外。例如,在CDC 6000系列科学大型计算机中,一字节由6位组成。
在C和C++编程语言中,在数字前加上0x(即数字0和小写字母x)表示该数字以十六进制表示,如果在数字前仅加上0,则表示八进制。C++允许在数字前加上0b来表示二进制。尽管用于指定二进制的0b记法并非标准C的一部分,但gcc编译器允许这样做。因此,本书在编写C或C++代码时,以下都是等同的:
100 = 0x64 = 0144 = 0b01100100
但如果你使用的是其他C编译器,可能无法使用0b语法指定二进制。
1.用十六进制表示以下位模式:
a.0100 0101 0110 0111
b.1000 1001 1010 1011
c.1111 1110 1101 1100
d.0000 0010 0101 0010
2.用二进制表示以下十六进制模式:
a.83af
b.9001
c.aaaa
d.5555
3.下列各个值需要用多少位表示?
a.ffffffff
b.7fff58b7def0
c.1111 2
d.1111 16
4.下列若干位可以用多少十六进制数位表示?
a.8位
b.32位
c.64位
d.10位
e.20位
f.7位