您的位置:首页 > 编程语言 > C语言/C++

C语言进阶【暑期特别篇】深入解剖(un)signed及溢出(中) 推荐

2013-07-28 17:53 567 查看

C语言学习笔记

之 深入剖析(un)signed char 及溢出

一:signed char 和unsigned char 的取值范围

Char和int 一样,都有有符号和无符号之说。即unsigned char和signed char。
1.C语言中我们用的char默认到底是有符号还是无符号的呢?
对于不同的教材会有不同的答案,其实有无符号都是自己电脑的编译器决定的。(注意:我的电脑默认是有符号的,以下实例都是按我的电脑默认的程序)
2. (有)无符号 char类型的取值范围。
我们知道char类型所占据的空间内存一般是1个字节(8位),signed char和unsigned char当然也是占1个字节8个位数。但是和int类型一样,它们的取值范围是有区别的。
Unsigned char类型的取值范围是:0~255
Signed char类型的取值范围是:-128~127

二:signed char 和 unsigned char 的溢出问题

其值在范围内时,会被正常处理,但是超过范围就会发生我们所说的溢出。但是要注意的是,在范围之内也并不意味着它就是可打印的字符。
1. 来看一下unsigned char类型的溢出问题
关于上界溢出
十进制
二进制

254
1111 1110
254
255
1111 1111
255
256


257


关于下界溢出
十进制
二进制

2
0000 0010
2
1
0000 0001
1
0
0000 0000
0
-1


-2


我们已经说过了unsigned char 的取值范围是0~255,通过上述两个表格:
在上界中254,255都能正常表示,那256和257它们不在计算机分配的范围之内,它们是溢出了,那问号处的值应该怎么表示呢?
同样的,在下界中,0,1和2都在范围之内,能正常表示,-1和-2很明显溢出越界了,那怎么表示呢?
2.再来看一下signed char类型的溢出问题
关于上界溢出
十进制
二进制

126
0111 1110
126
127
0111 1111
127
128


129


关于下界溢出
十进制
二进制(补码形式)

-127
1000 0001
-127
-128
1000 0000
-128
-129


-130


我们也已经知道了signed char的取值范围是:-128~127.
在上界中,126和127在范围之内,都能正常显示值。但是128和129呢?
在下界中,-127和-128在范围之内,都能正常显示值。但是-129和-130呢?

三:signed char 溢出的表示

1.程序实例验证一下signed char中溢出的数字的值(求signed char溢出中的问题)
#include <stdio.h>
main()
{
signed char a=126,b=127,c=128,d=129;
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
}




#include <stdio.h>
main()
{
signed char a=-127,b=-128,c=-129,d=-130;
printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
}




从上述两个程序中,我们不难得出以下结论的表格数据。
2.给出signed char溢出问题表格的答案:
关于上界溢出
十进制
二进制

126
0..0 0111 1110
126
127
0..0 0111 1111
127
128
1..1 1000 0000
-128
129
1..1 1000 0001
-127
关于下界溢出
十进制
二进制(补码形式)

-127
1..1 1000 0001
-127
-128
1..1 1000 0000
-128
-129
0..0 0111 1111
127
-130
0..0 0111 1110
126
注:0..0 表示24个0,1..1表示24个1
3.解析
从上述两个表格中可以看到,不管是否超过上下届,不管是负数还是正数,每增加(减少)一个单位,就直接在二进制表示的最后一位上加(减)1个单位。
并且相加和相减时,都先不看前24位,如果倒数第8位变为1,则前面24位全部设置为1,该数被解释为负数;如果倒数第8位变为0,则前面24位全部设置为0,该数被解释为正数。
我们来分别看看。
(1)126和127
126和127是范围之内的数字,他们的值是遵从规则的。所以他们的值也是126和127,并没有越界。
(2)128
从程序实验和上表的结论中,我们得出了128的值竟然是-128.128这个数字是越界的数字,是127+1。
这时会在127的最后8位上加1,也就是在0..0 0111 1111的后8位0111 1111上加1,变为1000 0000。倒数第8位变成了1,所以前24个位也全部变为1,所以该数被表示为负数。它的值为 -1*2^7+0=-128。
根据负数的值在计算机中是以补码的形式存储的理论,也就是说1000 0000是补码,即:-128在计算机中是以1000 0000存储的,-128的原码是1000 0000(补码)减1,再取反,结果还是1000 0000(原码)。
(3)129
129和128的取值也是一样的道理。129是127+2或者128+1,抛开前24位不说,它的二进制为1000 0001,倒数第8位为1,所以前24位也为1,并且为负数。所以它的值表示为: -1*2^7+1=-127.
根据负数的值在计算机中是以补码的形式存储的理论,1000 0001是补码,即:-127在计算机中是以1000 0001存储的,-127的原码是1000 0001(补码)减1,再取反,结果是0111 1111(原码)。
(4)-127和-128
这两个数字都是在范围之内 没有什么可说的了吧,并且它们的二进制形式也刚刚讲过了。
(5)-129
-129是-128-1所得,所以-128的最后8位是1000 0000,减去1变为0111 1111,前面24位全部置位0,且该数被解释为正数,其值为2^0+2^1+2^2+2^3+2^4+2^5+2^6=2^7-1=127
(6)-130
-127的最后8位是1000 0001,减去3变为0111 1110,前面24位全部保持0,且该数被解释为正数,其值为2^1+2^2+2^3+2^4+2^5+2^61=126

四:unsigned char 溢出的表示

看了上述的讲解 ,我相信读者一定对unsigned char也明白了,无符号无非就是取值范围不一样而已。不过我们还是来一起看一下。总觉得不放心 呵呵
1.程序实例验证一下unsigned char中溢出的数字的值(求unsigned char溢出中的问题)
#include <stdio.h>
main()
{
unsigned char a=254,b=255,c=256,d=257;
printf("a=%u\nb=%u\nc=%u\nd=%u\n",a,b,c,d);
}




#include <stdio.h>
main()
{
unsigned char a=1,b=0,c=-1,d=-2;
printf("a=%u\nb=%u\nc=%u\nd=%u\n",a,b,c,d);
}




从上述两个程序中,我们不难得出以下结论的表格数据。
2.给出unsigned char溢出问题表格的答案:
关于上界溢出
十进制
二进制

254
0..0 1111 1110
254
255
0..0 1111 1111
255
256
0..0 0000 0001
0
257
0..0 0000 0001
1
关于下界溢出
十进制
二进制

2
0..0 0000 0010
2
1
0..0 0000 0001
1
0
0..0 0000 0000
0
-1
0..0 1111 1111
255
-2
0..0 1111 1110
254
注:0..0 表示24个0,1..1表示24个1
3.解析
其实和有符号基本相同,唯一的差别就是,前面的24位一直都是0,并且该数永远都是正数。我们说几个吧。
比如256,256=255+1所得,255为0..0 1111 1111,然后加1,虽然255的全码都是1,再加1貌似没法加了,但是我们仍可将1111 1111前面一位加1,最后得到0001 0000 0000,之后我们就只看后8位即可,所以256的值是0.
比如-1,-1=0-1所得,0000 0000减1相当于减去0000 0001,虽然0的全码是0…0 0000 0000,似乎往上也没法借位,但是我们仍可将0000 0000前面一位加上1,看做0001 0000 0000减去0000 0000 0001,最后得到0000 1111 1111,我们直接取最后8为即可。

五:疑惑

对于无符号型,前24位永远为0,对于有符号型,前24位永远和倒数第8位一样。这个定律可要记清楚了
不知道和大家学习了有无符号char类型以及几个例子,有没有对unsigned 和signed了解了很多呢。在上一篇C语言进阶【暑期特别篇】深入解剖(un)signed及溢出(上)中的unsigned int和signed int其实和我们这一篇讲的是一个道理。
看完C语言进阶【暑期特别篇】深入解剖(un)signed及溢出(上)C语言进阶【暑期特别篇】深入解剖(un)signed及溢出(中)两篇文章后,我和读者都有一个问题和疑惑,在程序中定义什么类型就以什么类型输出的,如果不是呢?比如:变量a定义为unsigned(无符号),但是我们在输出的时候以signed(有符号)(%d)输出,那又会如何呢?相同的,定义为signed,但是以unsigned输出,结果又会是如何呢?
这个问题就在下一篇文章C语言进阶【暑期特别篇】深入解剖(un)signed及溢出(下)中学习吧。下一篇中我们主要是以一个实际的程序例子来展开陈述,来总结有无符号。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unsigned char sign