整数编码
本文介绍整数编码,主要讨论无符号整数和有符号整数的编码不同所带来的一些理解上的问题。无符号整数编码很容易理解,因其没有符号位,在二进制无符号整数转为十进制数时,每一位上的数字(0或1)乘以该为的权值2w-1(w从1开始),然后相加即可。对于有符号整数,最高位为符号位,符号位的权值决定了正负。有符号整数编码有原码、反码和补码三种方式。
1、原码和反码
原码的最高有效位是符号位,用来确定剩下的位应该取正权还是负权,表示如下:
反码的最高有效位的权值为-(2w-1-1),反码表示如下:
但是这两种编码对于0的编码都存在两种不同的编码方式,[00...0]解释为+0,而值-0在原码中表示为[10...0],在反码中表示为[11...1]。所以几乎所有的现在机器都使用补码来表示有符号整数。
2、补码
补码的最高有效位的权值为-2w-1,补码表示为:
对于0值,补码也是唯一 的编码[00...0]。以char型的有符号整数举例补码编码:
十进制 | 二进制 |
1 | 00000001 |
0 | 00000000 |
-1 | 11111111 |
3、有符号整数与无符号整数之间的转换
转换过程中二进制编码是不变的,也就是二进制中的每一位(0或1)是不变的,变的是计算的方式,例如:
无符号转为有符号:unsigned char x = 255,则(char)x的值为-1。
有符号转为无符号:char x = -127,则(unsigned char)x的值为129。
4、扩展一个整数的位表示
扩展一个整数的位时,要保证扩展之后的数与原数值相等。
- 无符号整数的零扩展:
对于无符号整数,扩展之后,在高位加0,例如八位二进制数[01000001]扩展为十六位时的表示为[0000 0000 0100 0001],高位全部为0。
- 有符号整数(补码)的符号位扩展:
对于有符号整数,符号位为正的,则高位全部为0,符号位为负的,高位全部为1。例如八位二进制数[1000 0001](十进制为-127)扩展为十六位时的表示为[1111 1111 1000 0001](十进制为-127),八位二进制数[0000 0001]扩展为十六位时的表示为[0000 0000 0000 0001]。
5、截断一个整数的位表示
对于无符号整数的截断很好理解,截断后的各位按照无符号编码进行计算,肯定为一个正整数。但是对于一个有符号整数的截断,则可能出现截断后,符号翻转的情况,因为截断后的最高有效位为0还是1来决定正负。
6、关于有符号整数与无符号整数的思考
由于编码的原因,很多时候考虑不周全就会出现意外情况,在扩展位或截断位以及强制转换的过程中,都需要仔细考虑各种情况。并且在整数运算的时候需要考虑溢出的情况,不同位数(char,short,int)的整数之间的混合运算和有符号与无符号的混合运算的情况。后两种情况的规则如下:
- 不同位数的整数之间混合运算时,需要首先将位数低的整数强制转换为位数高的整数,再进行运算
- 有符号与无符号整数之间的运算时,需要首先将有符号数转换为无符号数,再进行运算