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

Is left-shifting (<<) a negative integer undefined behavior in C++11?

本文关键字:lt 整数 C++11 左移 未定义      更新时间:2023-10-16

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

这里的相关标准段落来自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提供了对标准语的伪法典解释,简洁地表达了一种可能的(可能的)有效解释。 其他人质疑这个问题是否真的是关于语言"行为未定义"的适用性,而不是我们(StackOverflow)使用短语"未定义的行为"。 这个编辑是为了进一步澄清我想问的问题。

@Angew对《标准》的解释是:

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

旁注,从 psudocode 的角度来看待这个问题,我心中很清楚@Agnew的解释是正确的。

是的,我会说它是未定义的。如果我们将标准代码转换为伪代码:

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;

我想说的是,他们之所以明确使用右操作数而不是左操作数,是因为您引用的 paragrpah(带有右侧操作数大小写的参数)适用于左移位和右移位。

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

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

是的,当给定任何负数时,行为是未定义的。仅当满足以下两个条件时,才会定义该行为:

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

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

if X and Y
  then Z
else U

根据问题回答:

真正的问题是:

我们是否可以将术语"

行为未定义"完全等同于术语"未定义的行为"。

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

个人对情况的评论

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

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