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. 有符号短整型 下界溢出综合实例
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#
include
<stdio.h>
main()
{
short
int
st1=-
32770
,
st2=-
32769
,
st3=-
32768
,
st4=-
32767
,
st5=-
32766
;
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.有符号短整型上界溢出 综合实例
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#
include
<stdio.h>
main()
{
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.无符号整型下界溢出 综合实例
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#
include
<stdio.h>
main()
{
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. 无符号整型下界溢出 综合实例
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#
include
<stdio.h>
main()
{
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及溢出的问题就全部和大家探讨完了! 如果还有问题的话,欢迎留言询问。