有符号溢出和无符号溢出的讨论

本文总结了C语言中signed和unsigned类型的使用和溢出问题,通过多个实例详细解释了不同情况下输出的正负数表示,帮助读者理解和避免常见错误。

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. 有符号短整型 下界溢出综合实例


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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);
}


解析:

 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.有符号短整型上界溢出  综合实例


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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);
}


 解析:

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.无符号整型下界溢出 综合实例


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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);
}


解析: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. 无符号整型下界溢出 综合实例


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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);
}


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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值