不知何为原码反码补码的童鞋请猛戳这里,这篇文章要说的是,数据类型的取值范围和溢出
-
取值范围
数据类型的取值范围有一个公式:-2(n-1)~2(n-1)-1
n为整型的内存占用位数,所以int类型32位那么就是-(231)~231 -1即-2147483648~2147483647
但是,为什么最小负数绝对值总比最大正数多1???
以char为例:
-0:原码是1000 0000,补码为1 0000 0000,由于char是八位,所以取低八位0000 0000。+0:原码为0000 00000,补码为也为0000 0000,虽然补码0都是相同的,但是有两个0,既然有两个0,况且0既不是正数,也不是负数,用原码0000 0000表示就行了,这样一来,有符号的char,原码都用来表示-127~127之间的数了,唯独剩下原码1000 0000没有用
现在再来探讨一下关于剩下的那个1000 0000
-128的原码是1 1000 0000,9位,最高位符号位,再算它的反码1 0111 1111,进而,补码为1 1000 0000,这是-128的补码,发现和原码一样,但是在char型中,是可以用1000 000表示-128的。关键在于char是8位,它把-128的最高位符号位1丢弃了,截断后-128的原码为1000 0000和-0的原码相同,也就是说1000 0000和-128丢弃最高位后余下的8位相同,所以才可以用-0表示-128。这样,当初剩余的-0(1000 0000),被拿来表示截断后的-128,因为即使截断后的-128和char型范围的其他数(-127~127)运算也不会影响结果,所以才敢这么表示-128
-
数据溢出
既然说-128和char型范围的其他数(-127~127)运算也不会影响结果,那么我们就来运算一下,运算完之后也就知道了数据溢出是怎么回事了:(注意计算机内部以补码形式进行运算的,所以运算结果为补码,补码转原码的过程为:先减一,然后符号位不变其他位取反)
- 128 + 127:
1000 0000
+ 0111 1111
= 1111 1111,符号位为1表示负数,减一得到反码1111 1110,取反得到源码1000 0001,即-1
127+(-127):
0111 1111
+ 1000 0001
= 1 0000 0000,高位溢出,取后八位,得0
-128+(-1):
1000 0000
+ 1111 1111
= 1 0111 1111,高位溢出,取后八位,符号位为0表示正数,所以得127
127+1:
0111 1111
+ 0000 0001
= 1000 0000,前面我们已经讨论过,1000 0000表示-128
搞清了数据类型的取值范围和溢出,并且知道计算机内部是以补码形式进行运算的,那么也就不难理解为什么下面这个程序会输出-1了
#include<stdio.h>
int main()
{
//1111 1111
//1111 1110
//1000 0001
char c = 0xff;
printf("%d\n",c);
}