0x80000000为什么等于-2147483648和负数如何在内存上储存

1 篇文章 0 订阅
1 篇文章 0 订阅

1·先说明负数怎么储存

(1)十进制负数是以其补码储存在内存上。

验证:求-8在内存上以二进制形式1的个数

思路是:拿变量,令值为1,与-8的二进制码的每一位做与运算,若与运算结果为1,则该位为1。

代码:

int NumberOf1(int n) {
  int count = 0;
  unsigned int  value = 1;
  while (value != 0) {
     if (value&n) {
       count++;
     }
     value = value << 1; //左移右边补0,当移完32为value为0.
   }
   return count;
}

结论:

输入-8,结果为29。

在32位系统上,-8的储存

-8的储存是以-8的补码,储存在内存上。

-8的原码 1000 0000 0000 0000 0000 0000 0000 1000

取反 由于第一位是符号位 不用改变 得:1111 1111 1111 1111 1111 1111 1111 0111 

补码=反码+1 得::1111 1111 1111 1111 1111 1111 1111 1000 

得到1的数量正好为29,所以-8的补码就是-8储存在内存上的二进制码

(2)但是在十六进制,负数在内存中储存的是原码

(这个结论是错误的,但是验证过程和结果是正确的,正确的结论请移步到最后面,可以了解此过程,帮助理解)

验证:

对int test = 0x80000001 (对应十进制为-1) 检查其内存上的1的个数,发现只有2个1

故内存上原码为  1000 0000 0000 0000 0000 0000 0000 0001.

对十六进制的-8也是2个1

 

(3)我们来看看0x80000000的输出

0x80000000 的二进制位

原码 1000 0000 0000 0000 0000 0000 0000 0000

 

若最高位为符号位,则为-0,可是输出int i = 0x80000000 发现i= -(2^31)

原因是在十六进制中负数的二进制原码的最高位是符号位,后面的31位为序号位,不是值位。1后面的000 0000 0000 0000 0000 0000 0000 0000,表示序号1,表示负数中,从小到大的第一位。

由于int的最小值为-2^31,排在负数从小到大的序号1,所以int i = 0x80000000 输出为 -(2^31)

我们来看看0xFFFFFFFF

原码 1111 1111 1111 1111 1111 1111 1111 1111

最高位为1 ,为负数,序号位为第(2^31)-1位  (111 1111 1111 1111 1111 1111 1111 1111=(2^31-1) 所以0xFFFFFFFF为负数从小到大 第2^31-1位 ,即

-2^31+2^31-1= -1    

输出int i = 0xFFFFFFFF 为 -1 符合

(4)十进制的补码也符合 符号位+序号位的原则

就拿-8来做例子:

-8的补码:1111 1111 1111 1111 1111 1111 1111 1000 可以看出最高位为1 序号位为第2^(31)-8位,(111 1111 1111 1111 1111 1111 1111 1000 = 2^(31)-8 )

则该补码表示的值为2^31- 2^(31)-8 = -8  符合

花费了2~3个小时去查阅相关内容,发现,目前较少相关信息,总结了一下发在这,是对自己学习成果的尊重,同时也希望对大家有点用。

觉得写得不错的点个赞,留个言。欢迎指正

------------------------------------------------------------------------

相关知识点补充:

十六进制用最高位作为符号位,1位负数,0为正数。

负数的位右移运算:

原则:若右移的数字为负值,则向右移动N位同时N个1补充在左边

若为正值,则以N个0补充在左边 

下面重头戏。。。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 两年后整理博客,发现此博客评论中存在不同的意见,其中有一个观点引起了我注意:补码的引入是为了简化电路设计,如果操作系统对不同的进制使用不同的存储方式,会增大电路设计的复杂度

我非常认同这个观点,也有不少质疑十六进制存储原码的声音,所以我再研究了一次负数如何存储在内存的问题!

先说结论:计算机数值一律采用补码来存储和表示,十六进制也不例外。

解释1(2)的现象:int test = 0x80000001 (对应十进制为-1) 检查其内存上的1的个数,发现只有2个1。

此现象是正确的,内存中存储的的确是0x80000001的二进制码。因为使用十六进制给int赋值时,这里的十六进制是补码形式。也就是说,我们给变量赋的是补码,不是源码,所以会直接把0x80000001这个补码存入内存。

再来解释0x80000000 = -2147483648

    先纠正一个错误认识:原码求值 != 补码 -1 再取反

        原码求值公式:

            补码的最高位有效位乘以(-1),然后按一般求二进制的方法求值,例如:

              0x80000001 = (-1)*1*2^31+ 0*2^30+....+1*2^0

              0x80000000 = (-1)*1*2^31+.....+0*2^0

              0x7FFFFFFF = (-1)*0*2^31+1*2^30+1*2^29+.....+1*2^0

             所以

              0x80000000 = (-1)* 1 * 2^31  = -2147483648

   破案啦,撒花啦~~~ 后面与技术无关是一些感言,只对技术感谢兴趣的可以离场啦

     (1)对被该博文误导的人感到非常抱歉,能力有限,实非有意!得到的教训是计算机学科不是物理学科,不要通过现象去假设一个理论,一般来说,计算机学科内的技术都是开放的,可以通过一些途径了解到具体的实现逻辑。(电子通信出身。。)

     (2)在再次查询资料的过程,发现不少其他博主完全copy了此文章(并且都排了个很好看的版,再看自己的排版,手动挡脸),说明该文章有帮助到他们,我的内心是很高兴的,但是希望博主们能尊重内容创造,转载时表明出处。

     (3)本人现在已经毕业1年多了,已经没有写C/C++很久了。目前在某企业从事JAVA微服务研发,已经有快1年的经验与积累,打算陆续把分布式架构中用到的中间件,微服务涉及到的一整套解决方案写成一个系列的专题博客,请大家多多支持,欢迎指正。

 

转载请标明出处。

评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值