1、每种数据类型存储的数据是有范围的,故超出该范围,数据会越限,造成数据错误。
例如:
int类型,占用4个字节,其范围是从-2147483648~2147483647
(为何是此范围,详见C语言中源码和补码详解_modi000的博客-CSDN博客_c语言源码补码)
上述为十进制范围,化为十六进制范围 0x8000 0000~0x7fff ffff
十进制 | 十六进制 | 二进制 | 实际打印及存储 |
-1 | 0x8000 0001 | 1000 0000 0000 0000 0000 0000 0000 0001 | 二进制:1111 1111 1111 1111 1111 1111 1111 1111 十六进制:0xffff ffff |
-2147483648 | 二进制:1000 0000 0000 0000 0000 0000 0000 0000 十六进制:0x8000 0000 | ||
2147483647 | 0x7fff ffff | 0111 1111 1111 1111 1111 1111 1111 1111 | 二进制:0111 1111 1111 1111 1111 1111 1111 1111 十六进制:0x7fff ffff |
总结:无论是正整数还是负整数, 存储的都是补码,只不过是正整数的补码是他本身;
正整数/负整数打印输出十进制数,显示其源码。
正整数/负整数打印输出十六进制数,显示其补码。
例如:
int a = -1;//源码:1000 0000 0000 0000 0000 0000 0000 0001
printf("%x\n",a); //输出的是补码:ffff ffff
因此,在整型出现越限后,判断越限后的结果是多少,需要先转换成二进制补码来看。
例1:
int a = 2147483648;
printf("%x\n",a); //输出的是8000 0000
printf("%d\n",a); //输出的是-2147483648
分析:注意:越限情况下,符号位需要多出来一位,如int型,此时符号位是在第33的位置上,然后按照这种形式算补码
二进制补码是:0 1000 0000 0000 0000 0000 0000 0000 0000 //正数源码和补码一致
只有32位,所以存储的是后32位,也就是-2147483648的补码。
例2:
int a = 2147483649; //正数源码和补码一致
printf("%x\n",a); //输出的是8000 0001
printf("%d\n",a); //输出的是-2147483647
分析:
二进制补码是:0 1000 0000 0000 0000 0000 0000 0000 0001
只有32位,所以存储的是后32位,也就是-2147483647的补码。
例3:
int a = -2147483649;
printf("%x\n",a); //输出的是7fffffff
printf("%d\n",a); //输出的是2147483647
分析:注意:越限情况下,符号位需要多出来一位,如int型,此时符号位是在第33的位置上。
二进制源码是:1 1000 0000 0000 0000 0000 0000 0000 0001
二进制补码是:1 0111 11111 1111 1111 1111 1111 1111 1111
保留后32位,结果为2147483647
例4:
int a = -2147483650;//输入是负数,输出为正数
printf("%x\n",a); //输出的是7ffffffe
printf("%d\n",a); //输出的是2147483646
分析:
二进制源码是:1 1000 0000 0000 0000 0000 0000 0000 0010
二进制补码是:1 0111 11111 1111 1111 1111 1111 1111 1110
保留后32位,结果为2147483646
总结:int型变量,正数越限1后,会变成最小的负数,越限2后,会变成倒数第二小的负数,依次类推。
负数越限1后,会变成最大的整数,越限2后,会变成第二大的正数,依次类推。
计算越限后值的步骤:
1)根据十进制数的正负情况在最高位前面一位添加符号位并转换成二进制数,正数,符号位为0,负数,符号位为1;
2)根据添加后的值情况 (包括新加的符号位)来计算补码,正数,不变;负数,取反加1,求补码;
3)去掉添加的符号位,获得最终计算机存储的数值,此数值的最高位为1,则取反加1转换为负整数,为0直接转化成十进制正数。
补充一种新的越限思路:
int a = 2147483648; 看成是2147483647 + 1;
也即:0x7f ff ff ff +1 = 0x80 00 00 00 // 是-2147483648 的补码;
int a = -2147483649;看成是-2147483648 -1;
也即:0x80 00 00 00 -1 = 0x7f ff ff ff //2147483647 的补码也是源码;
另外:对于无符号的数据类型越限的情况 unsigned char ch;范围是0-255;
unsigned char ch = 256;看成是255 +1;
也即:0xff +1 = 0x00(进位为1,舍去),故输出为0;
unsigned char ch = -1;看成是 0 -1;
也即:0x0 -1 = 0xff(从高位借位),故输出为255;
出现一个有趣的现象:
unsigned char ch = 255;
ch++; //ch =0;
ch--;// ch =255;
小结:发现unsigned 同 signed数据类型一样,越位后的值也是个循环。