C语言学习笔记
之(un)signed及溢出总结篇(下)
在学习了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 表示32个0. 1-1表示32个1. 0..0表示16个0. 1..1表示16个1.
2.概念理解总结
(1)指定类型,是指定了有效位数,并不是实际位数。计算机分配给我们的是32位即8个字节,我们指定变量a为short int即short int a。其实计算机给a分配了8个字节(32位),但是我们规定实际有效的位数只是后16位而已。这就是我们通常所说的short int 占2个字节。
(2)32位中的非有效位全部都与有效位的最高位一致。如果有效位最高位为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); } |
解析:
(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位,-32767是1..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); } |
解析:
(1)32765、32766和32767都没有溢出,且都是正数,有无符号输出都是一样的。
(2)32768发生了溢出,32768=32767+1,即 0..0 0111 1111 1111 1111加1,得到
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); } |
解析:0-0表示32个0
(1)-1:-1发生了溢出,当以%d输出时,依然是-1,当以%u输出时,-1=0-1,即:0-0减1,虽然0-0不能再减1了,并且32位前面也没有位数了,但是我们依然认为可以向第倒数33位借一个1.也就是1 0-0减去1,结果就是: 1111 1111 1111 1111 1..1。此数4294967295
(2)0、1和2都没有溢出,并且都是正数,所以他们原样输出。
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); } |
这个解析就不用我说了吧 !
至此,关于(un)signed及溢出的问题就全部和大家探讨完了! 如果还有问题的话,欢迎留言询问。
转载于:https://blog.51cto.com/zhaoyuqiang/1263844