讲解整数的存储之前,首先要了解原码、反码和补码这几个概念。
将一个整数,转换成二进制,就是其原码。例如单字节5的原码为0000 0101,-5的原码为1000 0101。
正数的反码就是其原码;负数的反码是将原码中除符号位以外的每一位取反。例如单字节5的反码为 0000 0101,-5的反码为 1111 1010。
正数的补码就是其原码;负数的补码是其反码加1。例如单字节5的补码为 0000 0101,-5的原码为 1111 1011。
在计算机内存中,数值一律采用补码表示。使用补码可以将符号位和数值域统一处理,使用加法电路来计算减法,简化了硬件电路。
例如,16-9 = 16+(-9),16 的补码为 0001 0000,-9 的原码为 1000 1001,补码为 1111 0111。我们可以直接将两个数的补码相加:
1111 0111 + 0001 0000 = 1 0000 0111
最高位的1溢出,被截去,内存中最后剩下 0000 0111,也就是7。
在《C语言中的整数(short,int,long)》一节中我们看到,当整数发生溢出时,结果有可能是一个古怪的值。请看下面的代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
short a = 0XFFFF;
short c = -1;
printf("a=%hd\n", a);
printf("c=%#hX\n", c);
system("pause");
return 0;
}
运行结果:
a=-1
c=0XFFFF
0XFFFF 为正数,其原码为 1111 1111 1111 1111,正数的补码和原码相同。变量 a 被赋值 0XFFFF 后,就发生了溢出,占用了符号位,使符号位变为1。%hd 表示以有符号数的形式输出,此时计算机检测到符号位为 1,所以被判定为负数。输出负数时,要由补码逆推出原码,现在数值域是 111 1111 1111 1111,它的原码为 000 0000 0000 0001,所以输出结果为 -1。
-1 为负数,其原码为 1000 0000 0000 0001,求得其补码为 1111 1111 1111 1111。%#hX 表示以无符号十六进制形式输出,并加前缀 0X。无符号数也即整数,此时不再有符号位,所有位都用来表示数值,所以输出结果为 0XFFFF。