【运算符的几个小坑点】unsigned int32 x = -1 >> 2 = 4294967295?

  • 今天闲谈时候的一点复习、发现和研究。
    为了解决这个问题,我们需要一些前置知识点。

第一步:原码,反码,补码

  • 在现在大部分计算机,我们使用 补码 存储数值。
    如果是有符号值 signed ,最左边的一位符号位,其他的都存储数值。
    符号位,我们规定 0 表示正数,1 表示负数
  • 原码
    即第一位是符号位,后面用二进制表示数,不足用前导 0 补足。
  • 我们规定正数的补码就是原码本身
    如果是8位情况下:
    比如 3 ,原码和补码都是 0000 0011
  • 我们规定反码就是原码每一位取反
    比如 -0 的反码就是 1111 1111
  • 然后我们发现,如果用反码表示数,那么 +0-0 表示不一致了!
    这个时候我们用到 补码:就是反码加一。
    比如 -0 的补码就是 1111 1111 + 1 = 0000 0000 (第一个1上溢了)
    比如 -2 的原码是 1000 0010 反码是 0111 1101 补码是 0111 1110

第二步:无符号数

  • unsigned 无符号数,自然本来第一个符号位的 bit 就改为存储值了。
    于是 unsigned int4 (-1) = 1111(b) = 15
    无符号数不是符号位永远是0!

第三步:无符号数情况下的位移运算符

  • 如果 unsigned int32 x = -1
    那么输出的 x = 1111 1111 1111 1111 1111 1111 1111 1111 = 4294967295
    我们已经是知道了。
    如果我再求 x = x >> 2 ,是多少呢?很明显,右移两位,会导致左边两位空出来,就变成:
    x = 0011 1111 1111 1111 1111 1111 1111 1111 = 1073741823

第四步:有符号数情况下的位移运算符

  • 坑点在这里:题目要求的 -1 >> 2 并不等于 -(unsigned int)1 >> 2 请注意!
    所以这里的位移运算符是针对有符号数,也就是默认的 (int)-1 的!
    对于有符号数的左移运算符,右侧补充0
    对于有符号数的右移运算符,左侧补充符号位
  • 举例子吧。下面为有符号数。
    3 = 0011(b) 那么 3 << 1 = 0110 = 6
    -1 = 1111(b) 那么 -1 << 1 = 1110 = -2
    可以看出,左移在没有进位到符号位的前提下,都是等于原来的数乘以 2 k 2^k2k
    3 = 0011(b) 那么 3 >> 1 = 0001 = 1
    -1 = 1111(b) 那么 -1 >> 1 = 1111 = -1
    -3 = 1101(b) 那么 -3 >> 1 = 1110 = -2
    可以看出,正数右移,左侧补 0 00相当于原来的数除以2向下取整。
    负数右移,左侧补 1 11。注意到,此时仍然相当于原来的数除以2向下取整。
    同理 − 1 > > k = − 1 -1 >> k = -11>>k=1 只要 k kk 是非负数都是成立的。

第五步:题目的解答

  • unsigned int32 x = -1 >> 2 = (int)-1 = 1111 1111 1111 1111 1111 1111 1111 1111(b) = 4294967295
  • 如果我们强制类型转化一下,答案就截然不同了
    unsigned int32 x = (unsigned)-1 >> 2 = 0011 1111 1111 1111 1111 1111 1111 1111(b) = 1073741823
    这个等价于:
    unsigned int32 x = -1;x >>= 2;

再提一嘴

  • 如果出现 x << -5 其实就相当于 x >> 5
    如果出现 y >> -6 其实就相当于 y << 6
    上述所有数值都在 Code Blocks 中测试过一遍。

版权声明:本文为weixin_45775438原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。