神奇的int i = -2147483648,为什么在VS中编译错误?

我们先从二进制机器标识码说起
  • 引用别人的一段话
    “这得从二进制的原码说起:
    如果以最高位为符号位,二进制原码最大为0111111111111111=215-1=32767 最小为1111111111111111=-(215-1)=-32767
    此时0有两种表示方法,即正0和负0:0000000000000000=1000000000000000=0
    所以,二进制原码表示时,范围是-32767~-0和0~32767,因为有两个零的存在,所以不同的数值个数一共只有216-1个,比16位二进制能够提供的216个编码少1个。 但是计算机中采用二进制补码存储数据,即正数编码不变,从0000000000000000到
    0111111111111111依旧表示0到32767,而负数需要把除符号位以后的部分取反加1,即-32767的补码为1000000000000001。
    到此,再来看原码的正0和负0:0000000000000000和1000000000000000,补码表示中,前者的补码还是0000000000000000,后者经过非符号位取反加1后,同样变成了
    0000000000000000,也就是正0和负0在补码系统中的编码是一样的。但是,我们知道,16位二进制数可以表示216个编码,而在补码中零的编码只有一个,也就是补码中会比原码多一个编码出来,这个编码就是1000000000000000,因为任何一个原码都不可能在转成补码时变成1000000000000000。所以,人为规定1000000000000000这个补码编码为-32768。 所以,补码系统中,范围是-32768~32767。

  • 因此,实际上,二进制的最小数确实是1111111111111111,只是二进制补码的最小值才是1000000000000000,而补码的1111111111111111是二进制值的-1。 ”

  • 因为当时的计算机普遍是16位,而现在的计算机普遍32位,所以上面的结论也就相应的变成了-2的31次方到2的31次方。这样的话范围是-2147483647~2147483647 但是由于人为规定的100000…000(31个0)为-2147483648,所以范围就变成了-2147483647~2147483647 。

  • 下面再讲一下关于算术溢出的问题的问题,溢出就是取模。弄懂了原码、补码的概念后,会发现其实都是有规律可循的。比如-1强制转换成unsigned int 后是4294967295.

  • int的范围是:-2147483648~2147483647 unsigned int的范围是:0~4294967295。如果超出这个范围会出现循环比如-2147483648-1=2147483647;4294967295+1=0;

  • 也可以堪称是取模后的说,比如int的模是 2147483648(2的31次方)。unsigned int的模是4294967296(2的32次方);比如4294967297%4294967296=1(与超出范围得到的结果相同4294967297超出2所以-1+2=1);

  • 计算机的处理方式真的很神奇,这样最大的数+1变成了最小的数,最小的数-1又成了最大的数。所有的数都连成了一个圆环。

  • 在来看一段解释性代码

  auto a = -2147483648;
  auto b = 2147483648;
  auto c = 2147483647;
  cout <<a<<typeid(a).name()<<endl;
  cout <<b<<typeid(b).name()<<endl;
  cout <<c<<typeid(c).name()<<endl;
  • 结果如下
    在这里插入图片描述
  • 上面的是g++下的结果,放在VS2017上直接编译不通过。为什么呢?
  • 要注意的是-2147483648这个数虽然是int的下限,但是计算机在处理的时候先是2147483648再加上一个 - 运算符,但是2147483648这一步的时候已经超出的int的范围,所以它比较特殊,直接赋值int a=-2147483648。低版本的VS会有警告,而比较高版本的VS(比如像VS2017)直接编译不通过。因此我们看到在用 auto 让编译器来推断的时候,g++编译器直接推断出来 a=-2147483648 的 a 是long类型的。
  • 对于警告或者编译不通过的处理办法是使用 int a = - 2147483647-1 就没警告了或者可以编译通过,当然此时的 a就是int 类型了,或者是调用#include<Limits.h>里的常量INT_MIN也行。
  • 但是对于gcc或者g++是可以编译通过的,嗯嗯,还是开源的力量比较大。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值