C语言学习笔记

  之(unsigned及溢出总结篇(下)

        在学习了C语言进阶【暑期特别篇】深入剖析(un)signed及溢出(上)C语言进阶【暑期特别篇】深入剖析(un)signed及溢出(中)两篇文章后,大家是不是对有无符号有了一定的了解,但是依然会产生各种疑问,比如:定义的有符号类型的常量,发生溢出的时候以无符号类型输出会是怎样? 同样的,定义的是无符号类型的,但是以有符号类型输出又能输出个什么东西呢?

   如果你还是拿不准的话,看来还得跟随在下继续看这篇文章了!呵呵

在这篇文章中,首先我们会总结一下,然后具体看几个综合实例,相信大家看完之后应该对有无符号的问题再也没有疑问了。

一:总结(int类型作为总结)

 1.int类型的范围总结



十进制范围

二进制范围

32

unsigned  int

0~4294967295

0~ 1-1

     signed  int

-2147483648~2147483647

1000 0000 0000 0000 0..0~

0111 1111 1111 1111 1..1

16

short  unsigned   int

0~65535

0 ~ 1111 1111 1111 1111  

short  signed  int

-32768~32767

1..1 1000 0000 0000 ~

0..0 0111 1111 1111 1111

0-0 表示320.  1-1表示321.  0..0表示160.  1..1表示161.

 2.概念理解总结

1)指定类型,是指定了有效位数,并不是实际位数。计算机分配给我们的是32位即8个字节,我们指定变量ashort  intshort  int a。其实计算机给a分配了8个字节(32位),但是我们规定实际有效的位数只是后16位而已。这就是我们通常所说的short int 2个字节。

  232位中的非有效位全部都与有效位的最高位一致。如果有效位最高位为0,则非有效位全为0,反之则全为1,也就我们所说的负数。

  3.有无符号输出类型总结

1%d: 是输出有符号类型的。当用此符号打印时,只看有效位数,并且还要看最高位来决定正负

2%u: 是输出无符号类型的。 当用此符号打印时,不管原类型是什么,都看32位,并且全部都视为正数。

二:综合实例

1. 有符号短整型 下界溢出综合实例


#include <stdio.h>
main()
{
   /*
 有符号短整型:有效位数为16位 ,2个字节,范围【-32768,32767】
*/
 short int st1=-32770,  //溢出
         st2=-32769,  //溢出
         st3=-32768,
         st4=-32767,
         st5=-32766;
   //分别以有符号整型%d和无符号整型%u输出
   printf("st1=%d=%u\n",st1,st1);
   printf("st2=%d=%u\n",st2,st2);
   printf("st3=%d=%u\n",st3,st3);
   printf("st4=%d=%u\n",st4,st4);
   printf("st5=%d=%u\n\n",st5,st5);
}


110419742.png

解析:

 1-32770溢出了,-32770=-32768-2,也即是 1..1 1000 0000 0000 0000减去2,变成

0..0 0111 1111 1111 1110,所以是正的32766,因为32766是个正数,不论是有符号输出还是无符号输出,都是32766-32769也是一个道理。

2-32767没有溢出,有符号输出依然是-32767,但是无符号输出时候要求是正数输出,我们也已经说过,无符号%u输出要看32位,-327671..1 0111 1111 1111 1111,看32位的话,这个数的结果应该是:2^31+2^30+.....2^16+32767=4294934529

1.有符号短整型上界溢出  综合实例


#include <stdio.h>
main()
{
   /*
 有符号短整型:有效位数为16位 ,2个字节,范围【-32768,32767】
*/
   short int st1=32765,
         st2=32766,
         st3=32767,
         st4=32768, //溢出
         st5=327698;//溢出
   //分别以有符号整型和无符号整型输出
   printf("st1=%d=%u\n",st1,st1);
   printf("st2=%d=%u\n",st2,st2);
   printf("st3=%d=%u\n",st3,st3);
   printf("st4=%d=%u\n",st4,st4);
   printf("st5=%d=%u\n\n",st5,st5);
}


110526267.png

 解析:

1327653276632767都没有溢出,且都是正数,有无符号输出都是一样的。

232768发生了溢出,32768=32767+1,即 0..0 0111 1111 1111 11111,得到

1..1 1000 0000 0000 0000

     如果以%d输出,则只看后16位,前16为作为正负号的判断,即-1*2^15=-32768.

    如果以%u输出,则要看32位,不管原来的数是正数还是负数,都变为正数,即:

2^31+2^30+....2^16+32768=4294934528

3.无符号整型下界溢出 综合实例


#include <stdio.h>
main()
{
   /*
 无符号整型:有效位数为32位 ,4个字节,范围【0~4294967295】
*/
   unsigned int st1=-2,//溢出
            st2=-1,//溢出
            st3=0,
            st4=1,
            st5=2;
   //分别以有符号整型和无符号整型输出
   printf("st1=%d=%u\n",st1,st1);
   printf("st2=%d=%u\n",st2,st2);
   printf("st3=%d=%u\n",st3,st3);
   printf("st4=%d=%u\n",st4,st4);
   printf("st5=%d=%u\n\n",st5,st5);
}


110546971.png

解析:0-0表示320

 1-1-1发生了溢出,当以%d输出时,依然是-1,当以%u输出时,-1=0-1,即:0-01,虽然0-0不能再减1了,并且32位前面也没有位数了,但是我们依然认为可以向第倒数33位借一个1.也就是1 0-0减去1,结果就是: 1111 1111 1111 1111 1..1。此数4294967295

 2012都没有溢出,并且都是正数,所以他们原样输出。

4. 无符号整型下界溢出 综合实例


#include <stdio.h>
main()
{
   /*
 无符号整型:有效位数为32位 ,4个字节,范围【0~4294967295】
*/
   unsigned int st1=4294967293,
            st2=4294967294,
            st3=4294967295,
            st4=4294967296, //溢出
            st5=4294967297;//溢出
   //分别以有符号整型和无符号整型输出
   printf("st1=%d=%u\n",st1,st1);
   printf("st2=%d=%u\n",st2,st2);
   printf("st3=%d=%u\n",st3,st3);
   printf("st4=%d=%u\n",st4,st4);
   printf("st5=%d=%u\n\n",st5,st5);
}


110607839.png

这个解析就不用我说了吧 !

至此,关于(unsigned及溢出的问题就全部和大家探讨完了! 如果还有问题的话,欢迎留言询问。