数据类型的取值范围和溢出

2016-07-26  本文已影响371人  abb266389fd0

不知何为原码反码补码的童鞋请猛戳这里,这篇文章要说的是,数据类型的取值范围和溢出

数据类型的取值范围有一个公式:-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);
}
上一篇下一篇

猜你喜欢

热点阅读