前言
在我们日常生活中使用的数往往是十进制的,而当我们学习C语言后我们会接触到许多不同的进制并且时常需要去思考与使用这些不同的进制(尤其是2的幂相关的进制,因为这种计数系统比十进制更接近于计算机的二进制系统),所以学习和掌握这些不同进制是非常重要的。
本文将对八进制和十六进制(8和16都为2的幂)进行一些讲解。
通常情况C语言都假定整型常量是十进制的数,但在表达与计算机相关的值时,八进制和十六进制却十分方便。
十六进制,与二进制的转换
十六进制(hexadecimal或hex),是基于16的幂的计数系统。用0~15表示数,但是当数字有两位,如10、11时会产生歧义,指的是1和0还是10呢?所以我们用字母A~F来表示10~15的数,10表示为A,11即B,12即C,13即D,14即E,15即F。例如,十六进制数A3E(在C中写作0xA3E)其实是10 3 14,转化为对应的十进制数时也就是各个位去乘各个位的权重:10*16^2+3*16^1+14*16^0 = 2622。
当然,A~F也可以写成小写的字母,a~f。0xA3F == 0xa3f。
有一个非常重要的规律是:十六进制数的每一位数恰好由4位二进制数表示,或者说每一个十六进制位可以翻译为4个二进制位。
举例:十六进制的2可以表示为0010,十六进制6则是0110,所以十六进制数26的位组合(bit pattern)就是00100110,十六进制数63的位组合就是反过来,即01100010。
可以在计算器上证明一下(HEX即hexadecimal,十六进制;BIN即binary system,二进制):
可以看到这么转化的结果确实正确,是不是非常方便?
每个十六进制位都对应一个4位二进制数(即4个二进制位),所以两个十六进制位恰好对应一个8位二进制位,也就是一个字节。第1个十六进制位表示前4位,第2个十六进制位表示后4位。
由此,十六进制位非常适合表示字节值。我们调试时的内存窗口的一个00就是一个字节,把00写在一起是为了更明确地表示这是两个十六进制位也就是一个字节(没有了解过的朋友可以先跳过):
比如下面这个代码,我们在内存窗口,地址处输入&m、把列数改为4,可以看到存放m的值的四个字节(m为一个int类型也就是4个字节)
1d 08 00 00是8个十六进制位,两个写一起代表一个字节,正好是4个字节。
(为什么1d 08 00 00对应的十进制是2077,这涉及到大小端字节序,本文按下不表)
00000000 00000000 00001000 00011101
//2077的二进制序列
00011101 00001000 00000000 00000000
//小端字节序存储形式
0001 1101 0000 1000 0000 0000 0000 0000
//把4位放在一起刚好可以翻译一个十六进制位
1 d 0 8 0 0 0 0
//翻译为十六进制
1d 08 00 00
//2位十六进制位放一起代表一个字节
附图:
我们可以看到十六进制每位最大的数15,也就是F,等价二进制为1111,恰好是4个二进制位能表示的最大值,这也说明了我们最多需要4个二进制位就能表示一位十六进制数。
八进制,与二进制的转换
八进制(octal),是基于8的幂的计数系统。用0~7表示数字。如八进制的432(在C中写作0432),转化十进制即:4*8^2+3*8^1+2*8^0 = 282。
同样的,八进制与二进制之间也存在非常方便的转换方法,正如十六进制转换二进制一样。对于八进制来说,规律是每个八进制位对应3个二进制位。如,八进制的0277的二进制是10111111(更方便点看就是10 111 111)。用111转换0277的最后一个7,再用111转换0277倒数第二个7,最后用010转换2,而0277最前面的0只是八进制前缀(下面会说)。
附图:
我们可以看到八进制每位最大的数7,等价二进制为111,恰好是3个二进制位能表示的最大值,这也说明了我们最多需要3个二进制位就能表示一位八进制数。
表示进制的前缀
However,有一个问题:现在我们有一个数10000,我们可以说它是十进制、十六进制或者二进制,但是计算机会认为它是十进制、十六进制还是二进制呢?
所以在C语言中,我们用特定的前缀表示一个数是什么进制。0x或0X前缀用来表示十六进制数,举例来说17的十六进制表示是0x11或0X11
八进制的情况也是类似的,我们同样需要特点的前缀表示它是一个八进制数而非其他进制,我们采用的前缀是0,举例来说17的八进制表示为021。
我们需要记住的一点是,不同的进制只是服务于更方便的表示,不会影响数值被存储的方式。不管是写成17、 021还是0x11,这个数被存储的方式都是在计算机内部以二进制进行编码。
显示(打印)八进制与十六进制
当我们要让一个数以我们想要的进制显示时,就需要使用对应的转换说明。不同进制有不同的转换说明。我们最常用的%d就是以十进制显示数字;八进制显示数字,用的是%o;十六进制显示,用%x。如果我们还想要更清楚地表明显示出来的数是什么进制就需要把前缀一起显示,而显示前缀也有转换说明:%#o、%#x分别为八进制和十六进制带前缀的转换说明。当然,也可以改为大写,%#X。
演示程序
最好的掌握方法就是上手写代码,现在我们不妨写一个程序,以十进制、八进制、十六进制打印同一个数,不妨就打印2077吧:
到此,本文就结束了,祝阅读愉快^_^