浅析为什么 char 类型的范围是 : -128~+127
在 C 语言中。 signed char 类型的范围为 -128~127,每本教科书上也这么写。可是没有哪一本书上(包含老师)也不会给你为什么是 -128~127,这个问题貌似看起来也非常easyeasy。 以至于不用去思考为什么,不是有一个整型范围的公式吗: -2^(n-1)~2^(n-1)-1 (n为整型的内存占用位数)。所以
int 类型 32 位那么就是 -(2^31) ~ 2^31-1 即 -2147483648~2147483647,可是为什么最小负数绝对值总比最大正数多 1 。这个问题甚至有的工作几年的程序猿都模棱两可。由于没有深入思考过,仅仅知道书上这么写。
于是。我不得不深入思考一下这个被很多人忽视的问题。
对于无符号整数,非常easy,所有位都表示数值,比方 char 型,8位。用二进制表示为 0000 0000 ~ 1111 1111,1111 1111 最大即为十进制255。所以 unsigned char 的范围为 0~ 255,在这里普及一下 2 进制转十进制的方法。 二进制每一位的数值乘以它的位权(2^(n-1),n为自右向左的位),再相加,可得到十进制数。比方 :1111 1111 = 1*2^7 + 1*2^6 + 1*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
= 255 。
可是对于有符号整数,二进制的最高位表示正负,不表示数值。最高位为 0 时表示正数,为 1 时表示负数。这样一来,能表示数值的就剩下( n-1 )位了,比方 char a = -1; 那么二进制表示就为
1 0000001。1 表示为 0 0000001,所以 signed char 型除去符号位剩下的 7 位最大为 1111 111 = 127,再把符号加上,0 1111111 = 127,1 1111111 = -127。范围应该为 -127~127 。同理 int 类型也一样,可是问题出来了,教科书上是 -128~127 啊,以下就剖析一下这个惊人的奇葩。
再普及一下计算机内部整数存储形式。大家都知道计算机内部是以二进制来存贮数值的,无符号整数会用所有为来存储,有符号的整数。最高位当做符号位
,其余为表示数值。
这样貌似合理, 却带来一个麻烦。当进行加法时,1+1 :
0000 0001
+ 0000 0001
—————————
0000 0010 ……………… 2
当相减时 1-1=?
因为计算机仅仅会加法不会减法,它会转化为 1 + (-1) ,因此:
0000 0001
+ 1000 0001
____________________
1000 0010 …………… -2
1-1 = -2?
这显然是不正确了,所以为了避免减法运算错误。计算机大神们发明出了反码,直接用最高位表示符号位的叫做原码, 上面提到的二进制都是原码形式,反码是原码除最高位其余位取反,规定:正数的反码和原码同样,负数的反码是原码除了符号位,其余为都取反,因此
-1 的源代码为 1 0000001 ,反码为 1 1111110。
如今再用反码来计算 1+(-1) :
0000 0001
+ 1111 1110
————————
1111 1111 ………… 再转化为原码就是 1000 0000 = -0
尽管反码攻克了相减的问题,却又带来一个问题:-0 。既然 0000 0000 表示 0。那么就没有 -0 的必要, 出现 +0 = -0 = 0 ,一个 0 就够了。为了避免两个 0 的问题。计算机大师们又发明了补码。补码规定:
整数的补码是其本身。负数的补码为其反码加一 。所以。负数转化为反码需两个步骤, 第一,先转化为反码,第二: 把反码加一。
这样 -1 的补码为 1111 1111 ,1+(-1) :
0000 0001
+ 1111 1111
________________
1 0000 0000 …………………… 因为 char 为 8 位。最高位 1 被丢弃结果为 0 ,运算正确。
-0 :原码 1000 0000 的补码为 1 0000 0000 。因为 char 是 八位 ,所以取低八位 00000000。
+0 :原码 0000 0000 ,补码为也为 0000 0000 ,尽管补码 0 都是同样的,可是有两个 0 。既然有两个 0 ,况且 0 既不是正数,也不是负数, 用原码为 0000 0000 表示即可了。
这样一来,有符号的 char,原码都用来表示 -127~127 之间的数了。只有剩下原码 1000 0000 没实用。用排列组合也能够算出来,0 ???????,能表示 2^7 = 128 个数,刚好是 0~127。1 ???????。也能表示
128 个数,总共 signed char 有 256 个数,这与 -127~127 中间是两个 0 刚好吻合。
如今再来探讨一下关于剩下的那个 1000 0000。既然 -127 ~ 0 ~ 127 都有相应的原码与其相应,那么 1000 0000 表示什么呢,当然是 -128 了,为什么是 -128 呢。网上有人说 -0 即 1000 0000 与 128 的补码同样。所以用 1000 0000 表示 -128,,这我实在是不敢苟同。或者说
-128 没有原码。仅仅有补码 1000 0000,胡扯,既然没有原码何来补码,还有说 -128 的原码与 -0(1000 0000) 的原码同样,所以能够用 1000 0000 表示 -128,我仅仅能说。回答得不要那么牵强, 原码 1000 0000 与 -128 的原码实际上是不同的。
但为什么能用它表示 -128 进行运算。假设不要限制为 char 型(即不要限定是 8 位)。再来看,-128 的原码:1 1000 0000 ,9位,最高位符号位。再算它的反码:1 0111 1111。进而。补码为:1
1000 0000,这是 -128 的补码,发现和原码一样,1 1000 0000 和 1000 0000 同样?假设说一样的人真是瞎了眼了,所以,-128 的原码和 -0(1000 000) 的原码是不同的,可是在 char 型中,是能够用 1000 000 表示 -128 的,关键在于char 是 8 位,它把 -128 的最高位符号位
1 丢弃了,截断后 -128 的原码为 1000 000 和 -0 的原码同样。也就是说 1000 0000 和 -128 丢弃最高位后余下的 8 位同样,所以才干够用 -0 表示 -128,这样。当初剩余的 -0(1000 0000)。被拿来表示截断后的
-128,由于即使截断后的 -128 和 char 型范围的其它 (-127~127) 运算也不会影响结果。 所以才敢这么表示 -128。
比方 -128+(-1) :
1000 0000 ------------------丢弃最高位的-128
+ 1111 1111 ----------------- -1
________________
10111 1111 ------------------char 取八位,这样结果不对,只是没关系 ,结果-129本来就超出char型了,当然不能表示了。
比方 -128+127:
1000 0000
+ 0111 1111
————————
1111 1111 -------------- -1 结果正确, 所以,这就是为什么能用 1000 0000 表示-128的原因。
从而也是为什么 char 是 -128~127。而不是 -127~127 。short int 相同如此 -32768~32767 由于在 16 位中,-32768 为原码为 17 位,丢弃最高位剩下的 16 为 - 0 的原码相同。
另一个问题,既然 -128 最高位丢弃了。那么为什么还能打印出 -128 ?
//在内存中以补码1 1000 0000 存储,但因为是 char。所以仅仅存储 1000 0000
char a= -128; //既然最高位丢弃了。输出时应该是 1000 000 的原码的十进制数-0,但为什么能输出-128呢。 printf("%d",a);
我猜想是计算机内部的一个约定。就像 float 一样 ,能用 23 位表示 24 位的精度 。由于最高位默觉得 1,到时候把 23 位取出再加 1 便可。
-128 也是相同的原理,当数据总线从内存中取出的是 1000 000 。CPU 会给它再添最高一位,变为 1 1000 0000 这样才干转化为 -128 输出,不然 1000 0000 怎样输出?这当然是我的一种判断,详细怎么实现还得问 CPU 的设计者了。
再看一个样例:
char a=-129;
printf("%d",a); //会输入多少?? 结果为 127 ,为什么呢?
-129 在补码为 10 0111 1111 仅仅取后八位存储,即 0111 111 这个值刚好是 127 了。同理 -130 截断后为 126.....
如此按模轮回,关于模就先不探讨了。
那么:
unsigned char a= -1;
if( 1 > a){
printf("大于");
}else{
printf("小于");
}
结果是什么呢? 出人意料的是:小于。而不是大于。猫腻在你哪呢,还是存储问题:
a 为 unsigned 无符号。 它的八位都用来存储数值, 没有符号位,编译器把 -1 转换为补码为 1111 1111。但因为是无符号。计算机会把 1111 11111 当做是无符号来对待。自然就是 2^8 -1 = 255 了,所以相当于是 if( 1 > 255) 肯定是 printf("小于"); 了。
浅析为什么 char 类型的范围是 : -128~+127的更多相关文章
- 浅析为什么char类型的范围是 —128~+127
转载于daiyutage 在C语言中, signed char 类型的范围为-128~127,每本教科书上也这么写,但是没有哪一本书上(包括老师)也不会给你为什么是-128~127,这个问题貌似看起来 ...
- [转载]浅析为什么char类型的范围是 —128~+127
http://blog.csdn.net/daiyutage/article/details/8575248 在C语言中, signed char 类型的范围为-128~127,每本教科书上也这么写, ...
- 解读为什么有符号的char可表示范围是-128~+127
问:为什么有符号的char可表示范围是-128~+127? 要明白这个问题,首先要明白一下几点: 对于char和int计算机中以补码形式存在. 严格来说计算机就是傻逼,它只知道某个位上是0还是1. 我 ...
- C语言 1字节signed char的范围为什么是-128~127?
参考 1. 关于 -128 ,+128,-0,+0,-1 的反码补码 | 博客园 2. 八位二进制数为什么表示范围(-128~~+127)理解 | 博客园 无符号单字节范围 无符号单字节unsigne ...
- 转:浅谈char类型范围
在 C 语言中, signed char 类型的范围为 -128~127,每本教科书上也这么写,但是没有哪一本书上(包括老师)也不会给你为什么是 -128~127,这个问题貌似看起来也很简单容易, 以 ...
- 带符号的char类型取值范围为什么是-128——127
以前经常看到带符号的char类型取值范围是-128——127,今天突然想为什么不是-127——127,-128是怎么来的? 127好理解,char类型是8位,最高位是符号位,0正1负,所以011111 ...
- C语言基础(6)-char类型
1. char常量.变量 使用单引号‘’引起来的就是char的常量 ‘a’是一个char类型的常量 “a”是一个字符串类型的常量 1是一个int型的常量 ‘1’是一个char型的常量 char a; ...
- 在vs中char类型的实参与LPCWSTR类型的形参类型不兼容怎么解决?
今天在做 COS脚本解释器的时候,遇到了这个问题 先了解一下 LPCTCHAR 这个东东 LPCTSTR用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么 ...
- unsigned char 类型
在蓝牙4.0的开发中,很多数据类型都用到了 unsigned char ,我觉得用这个类型的一个原因是相比较于整型,它占的空间更少. 比如: unsigned char a = 1; // 占1个字 ...
随机推荐
- 洛谷 P1529 回家 Bessie Come Home
P1529 回家 Bessie Come Home 题目描述 现在是晚餐时间,而母牛们在外面分散的牧场中. 农民约翰按响了电铃,所以她们开始向谷仓走去. 你的工作是要指出哪只母牛会最先到达谷仓(在给出 ...
- 极路由4pro交叉编译c、c++的代码
首先在官方文档中下载SDK 极路由4pro是mtmips架构,即32位mips,小端的,因此下载这个 防止官方的下载链接失效,特意上传到百度网盘: 链接:https://pan.baidu.com/s ...
- HDU 4316 Contest 2
三个摄像头,在XOY上与立体的点求出在平面上的交点,然后求出凸包.三个凸包相交的面积即是所求,即是可以用半平面交的方法求解了. 模板题了.代码拿别人的. #include<cmath> # ...
- Struts(19)Struts集成
Struts2 MVC架构 模型视图控制器(Model View Controller)或MVC,MVC是俗称.是一种软件设计模式,用于开发Web应用程序.模型 - 视图 - 控制器模式是由下面三个部 ...
- codeforces7D Palindrome Degree(manacher&dp或Hsh&dp)
D. Palindrome Degree time limit per test 1 second memory limit per test 256 megabytes input standard ...
- WinCE C#程序,控制启动时仅仅能启动一个程序,使用相互排斥量来实现,该实现方法測试通过
</pre><pre code_snippet_id="430174" snippet_file_name="blog_20140718_5_46349 ...
- 【c语言】输入一个递增排序的数组的一个旋转,输出旋转数组中的最小元素
//旋转数组的最小数字 //题目:把一个数组最開始的若干个元素搬到数组的末尾.我们称之为数组的旋转. //输入一个递增排序的数组的一个旋转.输出旋转数组中的最小元素. //比如:数组{3.4,5,1, ...
- HDU 5353 Average
Problem Description There are n soda sitting around a round table. soda are numbered from 1 to n and ...
- Unity3D——加入剑痕效果(PocketRPG Trail插件)
首先非常感谢大家的支持,因为近期项目吃紧,所以更新的速度可能会有点慢!希望大家谅解,当然大家的支持是我最大的动力.我也会尽我所能写出更好的文章,当然因为本人是个新手并且工作的内容也不是unity3D. ...
- Spark 运行机制及原理分析