左移(<<)是C++ 11中的负整数未定义行为吗?

Joh*_*ing 13 c++ language-lawyer c++11

int在C++ 11中左移一个负的未定义行为?

这里的相关标准段落来自5.8:

2/E1 << E2的值是E1左移E2位的位置; 空位是零填充的.如果E1具有无符号类型,则结果的值为E1×2E2,比结果类型中可表示的最大值减少一个模数.否则,如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1×2E2,那么这就是结果值; 否则,行为未定义.

令我困惑的部分是:

否则,如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1×2E2,那么这就是结果值; 否则,行为未定义.

这应该被解释为左移任何负数是UB吗?或者它只是意味着如果你的LS为负数且结果不适合结果类型,那么它是UB?

而且,前面的条款说:

1 /移位运算符<<和>>组从左到右.shift-expression:additive-expression shift-expression << additive-expression shift-expression >> additive-expression

操作数应为整数或无范围的枚举类型,并执行整体促销.

结果的类型是提升的左操作数的类型.如果右操作数为负数,或者大于或等于提升左操作数的位长度,则行为未定义.

这使得明确表示对其中一个操作数使用负数是UB.如果UB对另一个操作数使用负数,我希望在这里也要明确.

所以,底线是:

-1 << 1
Run Code Online (Sandbox Code Playgroud)

未定义的行为?


@Angew 提供了对Standardese的psudocode解释,它简洁地表达了一种可能(可能)有效的解释.其他人质疑这个问题是否真的与"行为未定义"的语言的适用性相比,而我们(StackOverflow)使用了"未定义行为"这一短语.这个编辑是为了提供一些我想要问的更多说明.

@Angew对Standardese的解释是:

if (typeof(E1) == unsigned integral)
  value = E1 * 2^E2 % blah blah;
else if (typeof(E1) == signed integral && E1 >= 0 && representable(E1 * 2^E2))
  value = E1 * 2^E2;
else
  value = undefined;
Run Code Online (Sandbox Code Playgroud)

这个问题真正归结为这个 - 实际上是正确的解释:

value = E1 left-shift-by (E2)

switch (typeof(E1))
{
case unsigned integral :
  value = E1 * 2^E2 % blah blah;
  break;

case signed integral :
  if (E1 >= 0)
  { 
    if (representable(E1 * 2^E2))
    {
      value = E1 * 2^E2;
    }
    else
    {
      value = undefined;
    }
  }
  break;
}
Run Code Online (Sandbox Code Playgroud)

Sidenote,从psudocode的角度来看这个问题让我很清楚@Agnew的解释是正确的.

Rei*_*ica 8

是的,我会说这是未定义的.如果我们将standardese翻译为伪代码:

if (typeof(E1) == unsigned integral)
  value = E1 * 2^E2 % blah blah;
else if (typeof(E1) == signed integral && E1 >= 0 && representable(E1 * 2^E2))
  value = E1 * 2^E2;
else
  value = undefined;
Run Code Online (Sandbox Code Playgroud)

我会说他们明确右手操作数而不是左手操作数的原因是你引用的paragrpah(带有右手操作数的情况)适用于左右移位.

对于左手操作数,裁决有所不同.左移一个负数是未定义的,右移它是实现定义的.

  • @DeadMG嗯,你在技术上也可以"向左移动,但保持标志位不变." (2认同)

bam*_*s53 5

这应该被解释为左移任何负数是UB吗?

是的,当给出任何负数时,行为是不确定的.仅当满足以下两个条件时才会定义行为:

  • 这个数字是非负数
  • E1×2 E2可在结果类型中表示

这实际上是"如果E1具有有符号类型和非负值,并且E1×2 E2在结果类型中是可表示的,那么这就是结果值;否则,行为是未定义的",说:

if X and Y
  then Z
else U
Run Code Online (Sandbox Code Playgroud)