为什么整数溢出在有符号整数上是未定义行为,而在无符号整数上却不是?

3
将有符号整数溢出定义为未定义行为的目的是为了允许编译器进行优化。但同样也可以把无符号整数溢出定义为未定义行为,这是否也是一个合理的论点呢?

4
有不同的表示方法用于有符号整数,它们的溢出行为也不相同。据我所知,只有一种表示方法被用于无符号整数。 - Slava
请注意,在C++术语中,无符号整数永远不会“溢出”:它们只能“绕回”,因为标准规定对于无符号整数使用模算术。 - heap underrun
1
类型为“为什么语言设计者做出了这个决定而不是那个决定”的问题通常是没有答案的。 - n. m.
请参考以下线程:https://dev59.com/OWMl5IYBdhLWcg3wsIyA - Hari
1个回答

7
保持有符号整数溢出未定义的目的可能是编译器优化。但其最初原因是标准没有定义有符号整数的位表示法。不同的实现提供了不同的有符号整数表示法,它们的溢出特性也会不同。这只是因为标准没有定义这些溢出特性而被允许。
相比之下,无符号整数位表示法始终是明确定义的(否则,你无法有效地进行大量的按位操作),因此它们的溢出行为也可以被明确定义。
对于特定大小的无符号整数的逻辑运算,在该值表示法下,以最大无符号值+1为模运算。因此,标准有一种方法可以说明任何数学运算的结果:它是预期的数值结果模最大无符号值+1。
也就是说,如果你有一个16位无符号整数,它持有65535,并且你将1加到它上面,数值结果是65536。然而,在16位数字中得到的结果是0。这是标准定义的方式,因为这是特定位深度的布尔运算的工作方式。表示法定义了行为。
相比之下,不同的有符号整数形式具有不同的溢出特性。如果标准定义了16位有符号整数32767 + 1的特定含义,那么如果特定的有符号整数表示法没有自然地提供该答案,编译器将不得不更改如何将这些值相加以生成该答案。对于补码,此添加结果为-0。如果标准使其成为实际行为,则每个二进制补码实现都无法仅仅添加数字。它必须检查溢出并掩盖结果。
在每个数学运算中。
1是其他原因,例如大多数代码无法很好地定义它。也就是说,在有符号整数溢出的情况下,大多数代码如果被很好地定义,将会一样失败。

1
我不确定我理解了这个。有符号整数的表示是实现定义的;编译器不能对位的操作含糊其辞。那么为什么溢出行为不会遵循这个规则呢? - Sneftel
1
@Sneftel 例如:一些硬件使用了有符号数;一些使用了反码,其他硬件可能会在有符号溢出时陷入故障等。 - Richard Critten
@RichardCritten 是的,我意识到了。这也是我的评论所在。 - Sneftel
@Sneftel:表示是实现定义的,但它们的含义并不是。要定义整数溢出,必须有一个关于当您将最大有符号整数加1时得到什么数字的说明。定义这一点需要定义一个表示或强制所有表示执行必要的操作以符合特定答案。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接