为了账号安全,请及时绑定邮箱和手机立即绑定

为什么无符号整数溢出定义了行为,而有符号整数溢出却没有定义?

为什么无符号整数溢出定义了行为,而有符号整数溢出却没有定义?

C++ C
慕少森 2019-06-20 17:22:30
为什么无符号整数溢出定义了行为,而有符号整数溢出却没有定义?C和C+标准都很好地定义了无符号整数溢出。例如,C99标准 (§6.2.5/9)国家涉及无符号操作数的计算永远不能在flow上进行,因为不能用结果无符号整数类型表示的结果被减少为模,即大于可以由结果类型表示的最大值的数。但是,这两个标准都声明有符号整数溢出是未定义的行为。同样,从C99标准(§3.4.3/1)UndefiNed行为的一个例子是flow上整数上的行为。有历史的还是(更好的!)造成这种差异的技术原因?
查看完整描述

3 回答

?
富国沪深

TA贡献1790条经验 获得超9个赞

历史原因是,大多数C实现(编译器)只使用它使用的整数表示最容易实现的溢出行为。C实现通常使用CPU使用的相同的表示形式,因此溢出行为与CPU使用的整数表示相同。

在实践中,只有符号值的表示才可能因实现而不同:一个是补语,两个是补语,另一个是符号大小。对于无符号类型,标准没有理由允许更改,因为只有一个明显的二进制表示(标准只允许二进制表示)。

相关引文:

C99 6.2.6.1:3:

存储在无符号位字段和类型为无符号字符的对象中的值应使用纯二进制表示法表示。

C99 6.2.6.2:2:

如果符号位为1,则应以下列方式之一修改该值:

-符号位0的相应值被否定(符号和震级);

-符号位的值为−(2)N) (二补);

-符号位的值为−(2)N−1)(补足).


现在,所有处理器都使用两种补码表示,但签名算术溢出仍未定义,编译器制造商希望它保持未定义,因为它们利用这种不确定性来帮助优化。

查看完整回答
反对 回复 2019-06-20
?
哆啦的时光机

TA贡献1779条经验 获得超6个赞

除了Pascal的好答案(我肯定这是主要的动机)之外,还有可能一些处理器会导致有符号整数溢出的异常,当然,如果编译器不得不“安排另一种行为”(例如,使用额外的指令检查潜在的溢出并在这种情况下进行不同的计算),这当然会导致问题。

值得注意的是,“未定义的行为”并不意味着“不起作用”。这意味着在这种情况下,允许执行任何它想做的事情。这包括做“正确的事情”以及“报警”或“崩溃”。如果可能的话,大多数编译器都会选择“做正确的事情”,假设这是相对容易定义的(在本例中是这样的)。但是,如果计算中出现溢出,那么了解实际结果是很重要的,编译器可能会做一些您期望之外的事情(这可能非常取决于编译器版本、优化设置等)。


查看完整回答
反对 回复 2019-06-20
?
小唯快跑啊

TA贡献1863条经验 获得超2个赞

首先,请注意,C11 3.4.3和所有示例和脚注一样,都不是规范性文本,因此与引用无关!

声明整数和浮点数溢出是未定义行为的相关文本如下:

C11 6.5/5

如果在计算表达式过程中出现异常情况(即,如果结果没有数学定义,或者不在其类型的可表示值范围内),则行为是未定义的。

关于无符号整数类型的行为的明确说明可以在这里找到:

C11 6.2.5/9

有符号整数类型的非负值范围是对应的无符号整数类型的子范围,每个类型中相同值的表示形式是相同的。涉及无符号操作数的计算永远不会溢出,因为不能用结果无符号整数类型表示的结果将被减少,即大于结果类型所能表示的最大值的数字。

这使得无符号整数类型成为特例。

还请注意,如果有任何类型的转换到有符号类型时,旧值不能再表示。然后,这个行为仅仅是实现定义的,尽管可能会产生一个信号。

C11 6.3.1.3

6.3.1.3有符号整数和无符号整数

当具有整数类型的值转换为_bool以外的另一个整数类型时,如果该值可以由新类型表示,则它将保持不变。

否则,如果新类型没有符号,则通过重复添加或减去比新类型中可以表示的最大值多一个值来转换值,直到该值位于新类型的范围内为止。

否则,将对新类型进行签名,并且不能在其中表示值;结果要么是实现定义的,要么引发实现定义的信号。


查看完整回答
反对 回复 2019-06-20
  • 3 回答
  • 0 关注
  • 1153 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信