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 的解释是正确的。