【问题标题】:C++ left shift operationC++左移操作
【发布时间】:2019-04-01 14:01:16
【问题描述】:

这是我的代码

int a=2147483647; 
int b= a<<1;
cout<<"a="<<a<<",  b="<<b;

我得到的输出是- a=214783647, b=-2

a 的二进制表示是

0111 1111 1111 1111 1111 1111 1111 1111

通过将其移动 1 位,它将更改符号位并将 LSB 替换为 0。所以,我认为答案将是 -ve 并且幅度将减去 1,即 -2147483646 但它给出的结果为 -2 。请解释一下。

【问题讨论】:

标签: c++ bit-shift


【解决方案1】:

这是因为您的计算机使用 2 补码作为有符号值。 无符号移位值是0xFFFFFFFE,它是2 中的-2,而不是-2147483647

Shifting 是在 C 中定义的实现。

顺便说一句,-2147483647 在这样的 CPU 上是 0x80000001

【讨论】:

    【解决方案2】:

    [expr.shift]/1 E1 &lt;&lt; E2的值为E1左移E2位位置;空出的位用零填充。 ...如果E1 具有带符号类型和非负值,并且E1 × 2^E2 可以在结果类型的相应无符号类型中表示,则转换为结果类型的该值就是结果值;否则,行为未定义

    强调我的。您的程序表现出未定义的行为。


    编辑:经过仔细考虑,我不再认为这是未定义的行为。 2147483647*2 确实适合 unsigned intint 的“相应的无符号类型”。它到int 的转换不是未定义的,而只是实现定义的。使用二进制补码的实现来定义这种转换是完全合理的,以便2147483647*2 == -2,只是重新解释位模式,正如其他答案所解释的那样。

    【讨论】:

    • 请注意,引用的段落不再在 C++ 标准中。但是,这句话的含义相同:eel.is/c++draft/expr#pre-4.sentence-1.
    • 经过仔细检查,我不再认为这是未定义的行为。 2147483647*2 确实适合 unsigned intint 的“相应的无符号类型”。它到int 的转换不是未定义的,而只是实现定义的。使用二进制补码的实现来定义这种转换是完全合理的,以便2147483647*2 == -2,只是重新解释位模式。
    • @DanielLangr 您引用的标准草案defines left shift thusly:“E1 &lt;&lt; E2 的值是与E1×2^E22^N 一致的唯一值,其中N 是类型的宽度结果。”碰巧-2 == 2147483647*2 modulo 2^32。所以我认为标准草案实际上扩展了移位运算符的领域,并且很好地定义了原始表达式。
    • @IgorTandetnik 它没有。 2147483647 * 2就是4294967294,取模2^32(N=32是int类型的宽度)还是4294967294。而且这个数字不在int的可表示值范围内。
    • @DanielLangr 我不确定我是否遵循。 -2int 类型的唯一值,即 congruent 到 4294967294 模 2^32,不是吗?
    【解决方案3】:

    嗯,背后有一个很长的故事。

    由于int是有符号类型,所以表示第一位是符号,整个系统是二补码。

    所以 x = 0b 1111 1111 1111 1111 1111 1111 1111 0111 是 x = -9 例如 x = 0b 1111 1111 1111 1111 1111 1111 1111 1111 是 x = -1 和 x = 0b 0000 0000 0000 0000 0000 0000 0000 0010 是 2

    详细了解Two complement

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-30
      • 2011-03-12
      • 2021-04-26
      • 2019-09-06
      • 1970-01-01
      相关资源
      最近更新 更多