在C语言中,可以单独操控变量中的位。读者可能好奇,竟然有人想这样做,有时必须平单独操作位,而且非常有用。例如,通常向硬件设备发送一两个字节来控制这些设备, 其中每个位*(bit)*都有特定的含义。另外,与文件相关的操作系统信息经常被储存,通过使用特定位表明特定项,许多压缩和加密操行都是直接处理单独的位。高级语言一般不会处理这级别的细节, C在提供高级语言便利的同时,还能在为汇编语言所保留的界别上工作,这使其成为编写设备驱动程序和嵌入式代码的首选语言。
首先要介绍位,字节,二进制记数法和其他进制记数系统的一些背景知识。
二进制数、 位和字节
道都是基于数字10来书写数字,例如2157的千位是2,百位是1.,十位是5,个位是7。可以写成,
21000,1100+510+71。
注意,1000 是10的立方(即)3次幂),100是10的平方(即2次幂),10是10的1次幂,而且10(以及任意正数)的0次幂是1。因此,2157也可以写成:
2103+1102+5101+7100 ;
因为这种书写数字的方法是基于10的幂,所以称以10为基底书写2157。
姑且认为十进制系统得以发展是得益于我们都有10根手指。从某种意义上看,计算机的位只有2根手指。因为它只能被设置为0或1,关闭或打开。 因此。计算机适用基底为2的数制系统。它用2的幂而不是10的幂,以2为基底表示的数字被称为二进制教*(binary number)。二进制中的2和十进制中的10作用相同,例如。 二进制数1101可表示为,
123+122+021 +120
以十进制数表示为:
18+14+02+1*1
用二进制系统可以把任意整数(如果有足够的位)表示为0和1的组合。由于数字计算机通过关闭和打开状态的组合来表示信息,这两种状态分别用0和1来表示,所以使用这套数制系统非常方便、接下来,我们来学习二进制系统如何表示1字节的整教。
二进制整数
通常,1字节包含8位。C语言用字节*(byte)*表示存储系统字符集所需的大小。所以C字节可能是8位,9位,16位或其他值。不过,描述存储器芯片和数据传输率中所有的字节指的是8位字节。为了简化起见,本篇假设一字节是8位。可以从左往右给这8位分别编号为7—0。在一字节中,编号是7的位被称为高阶位,编号是0的位被称为低阶位。每一位的编号对应2的相应指数。
— 缺张图
这里,128是2的7次幕、以此类准。该字节能表示的最大数字是把所有位都设置为1,11111111。这个二进制数的值是,
128+64+32+16+8+4+2+1=255
而该字节最小的二进制数是00000000、其值为0。因此,1字节可存储0—255范围内的数字,总共256个值。或者,通过不同的方式解释位组合*(bit pattern)*、程序可以用1字节储存-128~127范围内总共还是256个值。例如,通常unsigned char用1字节表示的范围是0—255,而 signed char 1字节表示的范国是-128—127。
有符号整数
如何表示有符号整数取决于硬件、而不是C语言。也许表示有符号数最简单的方式是用1位(如,高阶位)储存符号,只到下7位表示数字本身(假设存储在1字节中)。用这种符号量表示法,10000001表示-1,00000001表示1。因此,其表示范围是-127~+127。
这种方法的缺点是有两个0,+0和-0。这很容易混淆,而且用两个位组合来表示一个值也有些浪费。二进制补码方法避免了这个问题、是当今最常用的系统。我们将以1字节为例,讨论这种方法。二进制补码用1字节中的后7位表示0~127,高阶位设置为0。目前,这种方法和符号量的方法相同。另外,如果高阶位是1,表示的值为负。这两种方法的区别在于如何确定负值。从一个9位组合100000000 (256的二进制形式)减去一个负数的位组合,结果是该负值的量。例如、假设一个负值的位组合是10000000,作为一个无符号字节,该组合为表示128,作为一个有符号,该组合表示负值(编码是7的位为1),而且值100000000-10000000,即1000000 (128)。因此,该数是-128(在符号量表示法中,该位组合表示-0)。类似地,10000001 是-127,11111111是-1。该方法可以表示-128—+127范围内的数。
要得到一个二进制补码数的相反数,最简单的方法是反转每一位(即0变为1、1变为0)、然后加1。因为1是00000001,那么-1则是11111110+1,或11111111。这与上面的介绍一致。
二进制反码方法通过反转位组合中的每一位形成一个负数。例如,00000001是1,那么11111110是-1。这种方法也有一个-0。该方法表示-127~+127之间的数。
二进制浮点数
浮点数分两部分储存,二进制小数和二进制指数。 下面我们将详细介绍。
二进制小数
一个普通的浮点数0.527. 表示如下:
5/10+2/100+7/1000
从左往右。各分母都是10的递增次幂,在二进制小数中,使用2的幂作为分母,所以二进制小数,表示为:
11/2+01/4+1*1/8
用十进制表示法为:
0.50+0.00+0.125
即是0.625.
许多分数(如,1/3) 不能用十进制表示法精确地表示。与此类似, 许多分数也不能用二进制表示法准确地表示。实际上,二进制表示法只能精确地表示多个1/2的幂的和。因此,3/4和7/8可以精确地表示为二进制小数,但是1/3和2/5却不能。
浮点数表示法
为了在计算机中表示一个浮点数,要留出若干位(因系统而异)存储二进制分数。其他位储存指数。一般而言。数字的实际值是由二进制小数乘以2的指定次幂组成。例知,一个浮点数乘以4,那么二进制小数不变,其指数乘以2,二进制分数不变。如果一份浮点数乘以一 个不是2的幂的数。 会改变二进制小数部分。如有必要,也会改变指数部分。
其他进制数
计算机界通常使用八进制记数系统和十六进制记数系统。因为8和16都是2的幂,这些系统比十进制系统使更接近计算机的二进制系统。
八进制
八进制*(octal)是指八进制记数系统。该系统基于8的幂, 用0-7表示数字(正如十进制用0-9表示数字一样)。例知,八进制数451 (在C中写作0451)表示为:
482+581+181 = 297(十进制)
了解八进制的一个简单的方法是,每个八进制位对应3个二进制位。下表列出了这种对应关系,这种关系使得八进制与二进制之间的转换很容易,例如,八进制教0377的进制形式是11111111。即用111代替0377中的最后一个7, 再用111代替倒数第二个7,最后用011 代替3,并舍去第1位的0。这表明比0377 大的八进制要用多个字节表示。这是八进制唯一不方便的地方:一 个3位的八制数可能要用9位二进制数来表示。注意,将八进制数转换为进制形式时, 不能去掉中间的0。例如,八进制教0173的二进制形式是01111011不是0111111。
八进制位 | 等价的二进制位 | 八进制位 | 等价的二进制位 |
---|---|---|---|
0 | 000 | 4 | 100 |
1 | 001 | 5 | 101 |
2 | 010 | 6 | 110 |
3 | 011 | 7 | 111 |
十六进制
十六进制*(hexadecimal或hex)是指十六进制记数系统。该系统基于16的幂,用0—15表示数字。但是,由于没有单独的数(digit,即0—9这样单独一位的数) 表示10—15,所以用字母A一F来表示。例如,十六进制数A3F (在C中写作0xA3F)表示为:
10162+3161+ 15160 = 2623(十进制)
由于A表示10,F表示15.在C语言中,A~F既可用小写也可用大写。因此,2623也可写作0xa3f。
由于每个十六进制位都对应一个4位的二 进制数(即4个进制位)。 那么两个十六进制位恰好对应一个8位字节。第1个十六进制表示前4位,第2个十六进制位表示后4位。因此,十六进制很适合表示字节值,下表列出了各进制之间的对应关系。例如,十六进制值0xC2可转换为11000010相反。二进制值11010101可以看作是1101 0101,可转换为0xD5。
十进制 | 十六进制 | 等价二进制 | 十进制 | 十六进制 | 等价二进制 |
---|---|---|---|---|---|
0 | 0 | 0000 | 8 | 8 | 1000 |
1 | 1 | 0000 | 9 | 9 | 1001 |
2 | 2 | 0010 | 10 | A | 1010 |
3 | 3 | 0011 | 11 | B | 1011 |
4 | 4 | 0100 | 12 |