前言:过年偷懒了(●ˇ∀ˇ●),但是年后开学了一定要恢复学习状态,在复习加继续学习的途中,我发现对于unsigned关键字的掌握并不是很熟练,于是翻阅了各个大佬的博客以及书籍,总结了对于unsigned的一些知识点。(如有不对的地方,欢迎各位大佬指正🤭)
什么是unsigned?
从字面上来看,不难理解,unsigned是无符号的意思,事实上,的确没错。它在C语言中和signed相反,signed是有符号的意思。其实C语言中的类型基本上都是有符号类型,只是省去了signed,
比如:(signed)int --> int
(signed char)-->char (这个取决于编译器,绝大多数编译器都是这个,比如我们常用的VS)
在了解什么是无符号之前,我们先了解一下什么是符号位:(知道的童鞋可以跳过了)
在计算机处理二进制数据时,专门规定了一位符号位,来确定数据的正负,这个符号位通常是数据的最高位,如8比特位数据,左边第一位就是符号位,剩下七位用来表示数据大小。
看例图:
在知道符号位之后就很容易理解无符号了,无符号嘛就是没有符号位,原来的符号位可以列入计算了。值得一提的是,无符号数都是非负数。
unsigned的深入理解
对于有符号类型的整形打印的时候用%d,对于无符号类型的整形打印时用%u
来看一下下面这几个典型例题,让你捋清它们之间的关系并且对unsigned有进一步的了解
例一:
我们将a初始化为无符号整形,将他以%u的形式打印时,我们知道整数在计算机中存储是以二进制序列补码的形式存储的,正数的补码和原码一样,但是负数的补码是通过原码到反码到补码转换得到的。(这个会放在最后说)
-1的补码是11111111111111111111111111111111(共计32位,因为int类型是4个字节,即32个比特位)
按照等比数列求和公式计算得到2^32-1=4294967295. 这与代码跑出来的结果一致。
但是以%d的形式打印时为什么是-1呢?因为以%d形式打印时,系统会将a认为是有符号整形,自然而然的将第一位视为了符号位,经过反码到原码的反变换得到原码是:10000000000000000000000000000001 即 -1。
我们经过调试发现在仅以%d形式打印完后,a的数值仍是4294967295。这说明在printf函数内部进行打印时以怎么样的类型打印并不改变数据原来的类型。
例二:
对于这个题中涉及到了整型提升,如果不理解整型提升是无法理解这道题的。
所以在解决这道题之前,先简单解释一下什么是整型提升
整型提升:
整型提升是C程序设计语言中的一项规定:在表达式计算时,各种整型首先要提升为int类型,如果int类型不足以表示则要提升为unsigned int类型;然后执行表达式的运算。
这是百度百科里面给的解释,是不是有些难以理解?那么来点通俗易懂的。
对于这道题来讲,就是以%d(4字节)打印的时候,不足四个字节的类型比如short,char等类型就要发生整型提升来补到4个字节,正数补0,负数补1(往左端补)。比如变量a,它的类型是char类型,大小是1个字节,它的补码是11111111,8个比特位,因为要以%d形式打印,所以要发生整型提升,就变成了11111111111111111111111111111111
打印时仍然为-1。
同样变量b的类型是short,大小为两个字节所以发生整型提升后也为11111111111111111111111111111111,结果为-1
变量c和变量d都是不足4字节的无符号整形,(无符号整形视为非负数)发生整型提升时前面补0,最终序列为
c:00000000000000000000000011111111 ---->2^8-1=255
d:00000000000000001111111111111111 ----->2^16-1=65535
而变量e本身就是4个字节,无需发生整型提升。因为是无符号整型,所以视为非负数,原码反码补码都一样,2进制补码为11111111111111111111111111111111
以%d形式(有符号整形)打印时第一位视为符号位,则视为负数,通过转换得到原码
10000000000000000000000000000001--->-1,最终结果为-1
由此我们得到结论:
对于负数:
//1.不发生整型提升的情况下,有符号数和无符号数以%u打印结果一样。(因为以无符号整型打印,都吧把符号位纳入计算)
//2.发生整型提升的情况下,有符号数前面补1,无符号数补0
例三:
通过之前的学习我们知道,sizeof是用来计算大小的单目操作符,那么a的类型是int,sizeof(a)是4,那显然-1<4啊,理应输出<,但是系统却输出了>,这是为什么呢?
通过查询MSDN我们发现sizeof返回值是size_t类型,也就是unsigned int类型。
那么在a和其做比较时,a会被转换为无符号类型作比较。a被转换为无符号类型后大小为2^32-1,显然大于4,所以输出 >
By the way:此处的a仍然为int类型,只是作比较时视为无符号类型哟,和之前的printf有异曲同工之处。
结论:在将一个有符号整形和无符号整形作比较时,会将有符号整形视为无符号整形来作比较,但不改变有符号整形变量的性质。
附:计算机中二进制数据的原码反码补码。
整形数据在计算机中存储时都是以补码形式存储的,因为:
补码使得符号位能与有效值部分一起参加运算,从而简化运算规则。
使减法运算转换为加法运算,进一步简化计算机中运算器的线路设计。
保证了0的唯一性,保证了数的表示的准确性。
对于正数来讲:
原码反码补码都相同
对于负数来说:
反码=原码符号位不变,其他位按位取反
补码=反码+1
举个例子:-10(以8bit位数据为例)
原码:10001010
反码:11110101
补码:11110110
结语:
对于整数其实不管怎么存,它的二进制序列是不变的,只是解释的方式不同,那么打印出来的数值就不同了.
ok辣,以上就是unsigned的详细讲解了。如有错误,欢迎指正qaq;如有不足,欢迎补充!
继续加油啊,还是那句话:路漫漫其修远兮,吾将上下而求索!!!