C++ 左移(<;<;)是C+;中未定义的负整数行为吗+;11?
在C++11中,左移是否为负C++ 左移(<;<;)是C+;中未定义的负整数行为吗+;11?,c++,c++11,language-lawyer,C++,C++11,Language Lawyer,在C++11中,左移是否为负int未定义行为 此处的相关标准段落来自5.8: 2/E1组的值从左到右。 移位表达式: 加法表达式 移位表达式>加法表达式 操作数应为整数或无范围枚举类型,且 执行整体促销 结果的类型是提升的左操作数的类型。这个 如果右操作数为负或更大,则行为未定义 大于或等于提升后的左操作数的位长度 这表明对其中一个操作数使用负数是错误的。如果对另一个操作数使用负数,我希望这里也能清楚地说明这一点 因此,底线是: -1 << 1 这个问题归根结底是这样的——实际上是
int
未定义行为
此处的相关标准段落来自5.8:
2/E1组的值从左到右。
移位表达式:
加法表达式
移位表达式>加法表达式
操作数应为整数或无范围枚举类型,且
执行整体促销
结果的类型是提升的左操作数的类型。这个
如果右操作数为负或更大,则行为未定义
大于或等于提升后的左操作数的位长度
这表明对其中一个操作数使用负数是错误的。如果对另一个操作数使用负数,我希望这里也能清楚地说明这一点
因此,底线是:
-1 << 1
这个问题归根结底是这样的——实际上是正确的解释:
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;
我要说的是,它们明确表示右操作数而不是左操作数的原因是,您引用的段落(具有右操作数大小写的段落)同时适用于左移位和右移位
对于左侧操作数,规则不同。左移负片未定义,右移负片已定义。根据问题回答:
问题是:
我们能否将“行为未定义”一词与“未定义的行为”一词完全等同
按照目前的措辞,它的意思是“未定义的行为”
对形势的个人评论
但我不相信作者的意图。如果这是作者的意图,那么我们可能应该有一个说明来解释原因。但我更倾向于相信作者的意思是,该操作的结果是未定义的,因为标准没有明确定义负数的表示。如果负数的表示没有为负数明确定义,那么移动位将导致未定义的值 无论哪种方式,措辞(或解释)都需要收紧/扩展,以减少歧义 这是否意味着任何负数左移都是UB 是的,当给定任何负数时,行为是未定义的。仅当以下两项均为真时才定义该行为:
- 这个数字是非负的
- E1×2E2可在结果类型中表示
if X and Y
then Z
else U
+我明白你在说什么。有没有想过为什么它们都只是实现定义的?也就是说,为什么有必要避免将负片左移到丢失玩具的地方?@johndilling真的不知道。我想说这是一个处理器架构专家的问题,对此我知之甚少。这不是关于位移位的唯一不对称。Java有
>>
,但没有@Angew:@DeadMG好吧,从技术上讲,你也可以有“向左移位,但保留符号位不变”。@Mike:据我所知,这种行为最初是未定义的,因为在这种情况下,可能在某个地方有一个实现会触发陷阱。几十年来,从未发现任何此类实施,它将被更改为实现定义,但这样做将不再允许编译器将任何会导致负数左移的事件链视为不可能。我理解,结果值可以是未定义的,因为标准没有明确设置负数的表示形式。但这难道不意味着操作的结果是未定义的吗?我不确定“行为未定义”是否完全等同于“未定义的行为”。我更倾向于认为作者的意思是结果值是未定义的(但无论哪种方式,语言都应该更严格)。@LokiAstari标准中已经有术语说明何时定义了行为,但不需要特定的值;它将表示该值未指定或不确定。如果这是我的意图,我希望使用这种语言。只要我们是语言律师……C++11之后,p2已经被CWG 1457修改过,如下所示:。这种调整的影响是,可以将有符号类型的1位转换为符号位,而在C++11之后,它现在不是未定义的行为。这样做是为了(例如)1@HowardHinnant供参考,我在回答这个问题时引用了你的评论。谢谢你的属性@神秘的:记住UB意味着包括理性在内的任何事情都可能发生。“行为是未定义的”是标准描述某事物调用UB的方式。只需计算“行为未定义”的命中率,实际上。使其未定义而非定义实现的一个有效原因是,某些移位的编译时计算结果与相同移位的运行时计算结果不同。定义它的实现将迫使实现进行选择,而选择意味着编译器的行为必须改变,这是有缺陷程序的唯一好处。我似乎很清楚,当标准说“行为未定义”时,他们的意思与我们(StackOverflow)说“未定义行为”时的意思相同,无论是在计算方法还是结果值中。毕竟,如果计算是未定义的,那么必须是r
if X and Y
then Z
else U