在C ++ 11中左移{负1 int
未定义行为?
此处的相关标准段落来自5.8:
2 / E1的值<&lt; E2是E1左移E2位位置;腾空 位是零填充的。如果E1具有无符号类型,则为 结果是E1×2E2,比最大值减少一个模数 在结果类型中可表示。否则,如果E1具有签名类型 和非负值,E1×2E2在结果中可表示 type,那就是结果值;否则,行为是 未定义。
困扰我的部分是:
否则,如果E1具有有符号类型和非负值,则E1×2E2 可以在结果类型中表示,那么这就是结果值; 否则,行为未定义。
这是否应该被解释为左移任何负数是UB?或者它只是意味着如果你LS为负数且结果不适合结果类型,那么它是UB?
此外,前面的条款说:
1 /移位运算符&lt;&lt;和&gt;&gt;从左到右组。 移位表达: 添加剂的表达 shift-expression&lt;&lt;添加剂的表达 shift-expression&gt;&gt;添加剂的表达
操作数应为整数或无范围的枚举类型 整体促销活动。
结果的类型是提升的左操作数的类型。该 如果右操作数为负数或更大,则行为未定义 大于或等于提升的左操作数的位数。
这明确表示对操作数的一个使用负数是UB。如果UB对另一个操作数使用负数,我希望在这里也可以明确。
所以,底线是:
-1 << 1
未定义的行为?
@Angew provided对替补的一种伪代码解释,它简洁地表达了一种可能的(可能的)有效解释。其他人质疑这个问题是否真的与“行为未定义”的语言的适用性相比,而我们(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;
}
旁注,从psudocode的角度来看这个问题让我很清楚@Agnew的解释是正确的。
答案 0 :(得分:8)
是的,我会说这是未定义的。如果我们将标准转换为伪代码:
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(右手操作数的情况)适用于左边和右边操作数。正确的转变。
对于左手操作数,裁决有所不同。左移一个负数是未定义的,右移它是实现定义的。
答案 1 :(得分:5)
这应该被解释为左移任何负数是UB吗?
是的,当给出任何负数时,行为未定义。只有满足以下两个条件时才会定义行为:
这实际上是“如果E1具有有符号类型和非负值,并且E1×2 E2 在结果类型中是可表示的,那么这就是结果值;否则,行为是未定义,“说:
if X and Y
then Z
else U
答案 2 :(得分:1)
问题确实是:
我们可以将术语“行为未定义”等同于术语“未定义行为”。
目前的措辞意味着“未定义的行为”。
但我不相信这是作者的意图 如果这是作者的意图,那么我们应该有一个说明解释原因。但是我更倾向于认为作者意味着该操作的结果是未定义的,因为标准没有明确定义负数的表示。如果没有为负数明确定义负数的表示,那么移动这些位将导致未定义的值。
无论哪种方式,措辞(或解释)都需要加强/扩展,以使其不那么模糊。