会飞的鱼

2020
Godam
首页 » 学习笔记 » C语言有符号数与无符号数的理解

C语言有符号数与无符号数的理解

引言

小编高中在学习JAVA的时候了解到有无符号数,一直不理解它究竟是什么意思,直到带着这个疑问四年一直到现在......

正文

在学习C++的时候决定去一探究竟——

    老王查找资料发现在x位系统中,有符号数表示的数值范围为-2 ^ (x-1)~2 ^(x-1)-1,无符号数表示的数值范围为0 ~ 2 ^ x-1,那么为什么是这个范围呢?


1.有符号数与无符号数的区别

    要想说明这个问题,首先我们要提到补码的概念,在数字电路课程里认识到了补码,这里就不做详解了(this->补码)那么,明白了补码的含义之后,我们可以知道32位二进制位中,最高位的权重为-1,换句话说,在无符号数中,最高位所代表的值是2 ^ 31,而在有符号数中,其表现方式是补码形式,最高位所代表的值是- 2^ 31。为了更加形象的来理解这句话的意思,我们用-1来作为一个例子。



    有一点值得注意的是:通常情况下,数字都默认为有符号类型。 因此这里的int a实际上就是signed int a;可见-1的二进制位表示为“11111111 11111111 11111111 11111111”。从这32中的最低位开始,每一位分别表示2 ^ 0、2 ^ 1、2 ^ 2、2 ^ 3…2 ^ 30,但是最高位就不一样了,按照有符号数的补码形式特点,其最高位的1表示的是负权的-2 ^ 31,这样,我们把每一位所表示的值加起来就是 - 2 ^ 31 +2 ^ 30+…+2 ^ 1+2 ^ 0=- 2 ^ 31+2 ^ 31-1=-1,可见其刚好就等于-1了,如果我们把程序中的a换成unsigned int类型,那么按前面所说的,最高位的1就应当表示为2 ^ 31,那么unsigned int(a)的值就应当是2 ^ 31 +2 ^ 30+…+2 ^ 1+2 ^ 0=2^32-1=4294967295,我们来看看是不是这样的呢:

    可以看到,运行结果完全符合我们的猜想。这就说明了有符号数和无符号数的区别:在32位编译器中,有符号数的二进制位最高位表示-2^ 31,而无符号数的二进制位最高位表示的是2^31。根据这一区别,我们就可以得到有符号数与无符号数的转换原理。

2.有符号数与无符号数的转换

2.1转换公式

    前面已经知道了有符号数与无符号数的区别,那么实际上就很容易得出二者的转换关系:假设一个数x,无论它是有符号数还是无符号数,它的二进制表示肯定都是唯一的(不可能在有符号形式下有一种表示,在无符号形式下也有一种表示),那么假设其二进制位中的最高位为m(m=0或1),其余位组合表示的数为n,打个比方,10的二进制表示为1010,那么它的最高位就是m=1,n=2(010),那么很明显,x=m*2^(w-1)+n,其中w为这个数的二进制位数,在32位编译器中w=32,64位编译器中w=64。

    以32位编译器为例,对于无符号数,由于其最高位代表2^31,因此x=m * 2 ^ 31+n ;而对于有符号数而言,由于其最高位代表-2 ^31,因此x=-m * 2 ^31+n,因此,无符号数要想转换为有符号数,就需要减上m * 2 ^32,那什么时候m为0什么时候m为1呢?很简单,对于无符号数来说,m为1表示x>=2 ^31,否则m=0;对于有符号数来说,m=1表示x<0否则m=0。由此得到转换公式如下:转换公式如下:

其中U代表无符号数,S代表有符号数,w表示编译器的位数。
2.2显式转换


    如图直接使用强制类型转换,十分简单粗暴。

2.3隐式转换

隐式转换主要在以下两种情况下发生:
①当一种类型的表达式被赋值给另外一种类型的变量时;
②当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么就会隐式地将有符号参数强制类型转换为无符号数。

对于第①种情况,如下所示:


    可见,输出的并不是-1,为什么不是-1而是4294967295呢?原因就在于unsigned int a=-1;这一句,前面说过,通常情况下,数字都默认为有符号类型。 因此这里的-1就是有符号类型,当它被赋值无符号型变量a时,-1就被隐式转换为无符号类型了,因此这里就需要采用前面的转换公式,-1+2^32=4294967295。

对于第②种情况,如下所示:


    如图所示,a=1,本身是大于-1的,应该返回true,但是由于这里a为无符号数,-1是有符号数,在进行“>”运算时,-1被强制转换成了无符号数,即成了4294967295,因此返回的真值是1>4294967295的真值结果,就是false。
这种情况往往对于标准的加减乘除运算来说并没有多大差异,但是对于“>”、“<”这样的关系运算符来说,结果就是非直观的了。


总结补充

    根据上面的总结,也能解决为什么a<b和a-b<0不等价?
    这是因为a<b可能引发b与a的隐式转换,即当a和b中一个为有符号类型,一个为无符号类型时,就会发现隐式转换,这种转换容易引起非直观的错误。如unsigned int a=1;int b=-1,此时a<b实际上是返回true的,而a-b<0则返回false;

    另一方面,a-b<0虽然也可能引发隐式转换,但是由于是减法运算,因此一般不会对结果造成影响,它最主要的问题是由于需要作减法运算,因此可能引发数据溢出的问题,比如说int a=-2147483648;int b=100;那么a<b肯定是返回true的,但是a-b实际上就溢出了,最终的a-b就成了一个正数,a-b<0也就返回false了。即使a和b都是无符号数,unsigned int a=1,b=2; 那么a<b肯定返回true的,但是a-b为负数就溢出了,但是a-b依旧是个正数,因此a-b<0也就返回false了。

    总的来说所谓有无符号,其根源还是来自数据在计算机中存储的特殊机制,了解了这一机制,其中的问题也就迎刃而解了。


文章参考

 https://blog.csdn.net/qq_28114615/article/details/85884280

文章如无特别注明均为原创! 作者: 果果, 转载或复制请以 超链接形式 并注明出处 GODAM|博客|godam
原文地址《 C语言有符号数与无符号数的理解》发布于2020-2-4

分享到:
打赏

评论

游客

切换注册

登录

您也可以使用第三方帐号快捷登录

切换登录

注册

sitemap