15

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

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

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

让我困惑的部分是:

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

这是否应该被解释为意味着左移任何负数都是UB?还是仅意味着如果您 LS 为否定并且结果不适合结果类型,那么它就是 UB?

此外,前面的条款说:

1/移位运算符 << 和 >> 从左到右分组。移位表达式:加法表达式移位表达式<<加法表达式移位表达式>>加法表达式

操作数应为整数或非范围枚举类型,并执行整数提升。

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

这清楚地表明,对操作数之一使用负数是 UB。如果是 UB 对另一个操作数使用负数,我希望在这里也能清楚地说明这一点。

所以,底线是:

-1 << 1

未定义的行为?


@Angew提供了对 Standardese 的伪代码解释,它简洁地表达了一种可能(可能)有效的解释。其他人质疑这个问题是否真的是关于“行为未定义”语言的适用性与我们(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;

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

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;
}

?

旁注,从伪代码的角度来看,我很清楚@Agnew 的解释是正确的。

4

3 回答 3

9

是的,我会说它是未定义的。如果我们将标准翻译成伪代码:

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;

我要说的是,他们明确指出右手操作数而不是左手操作数的原因是您引用的段落(具有右手操作数大小写的段落)适用于左移和右移。

对于左操作数,规则不同。左移负数是未定义的,右移是实现定义的。

于 2013-10-25T15:46:29.107 回答
5

这是否应该被解释为意味着左移任何负数都是UB?

是的,当给定任何负数时,行为是未定义的。仅当以下两个都为真时才定义该行为:

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

这就是“如果 E1 具有带符号类型和非负值,并且 E1×2 E2可以在结果类型中表示,那么这就是结果值;否则,行为未定义”的字面意思是:

if X and Y
  then Z
else U
于 2013-10-25T18:34:11.680 回答
1

根据问题回答:

问题真的是:

我们能否将“行为未定义”这一术语等同于“未定义行为”这一术语。

按照目前的措辞,它的意思是“未定义的行为”。

关于情况的个人评论

但我不相信这是作者的意图。
如果这是作者的意图,那么我们可能应该有一个说明解释原因。但我更倾向于相信作者的意思是该操作的结果是未定义的,因为标准没有明确定义负数的表示。如果没有为负数明确定义负数的表示,则移动位将导致未定义的值。

无论哪种方式,措辞(或解释)都需要收紧/扩展,以减少歧义。

于 2013-10-25T17:48:13.707 回答