整数溢出和未定义的行为

时间:2010-10-16 10:19:22

标签: c

由于可能undefined behavior,在实际加/减之前有很多关于检测整数溢出的问题。所以,我的问题是

为什么它会首先产生这个undefined behavior

我可以想到两个原因:

1)在这种情况下生成异常的处理器。当然,它可以切换,并且很可能是一个写得很好的CRT会做到这一点。

2)使用数字的其他二进制表示的处理器(1的补码?基数10?)。在这种情况下,未定义的行为将表现为不同的结果(但不会崩溃!)。好吧,我们可以忍受这一点。

那么,为什么有人会避免造成这种情况呢?我错过了什么吗?

4 个答案:

答案 0 :(得分:11)

虽然大多数现代CPU使用2的补码,并且整数溢出导致可预测的模数环绕,但这绝不是通用的 - 保持语言足够通用以使其可以在最广泛的范围内使用架构最好指定整数溢出是UB。

答案 1 :(得分:11)

虽然签名溢出的历史原因被指定为未定义的行为可能是这些虚假的遗留表示(补码/符号幅度)和溢出中断,但它保持未定义行为的现代原因是优化。正如J-16 SDiZ暗示的那样,签名溢出是未定义的行为这一事实允许编译器优化一些条件,其代数事实(但不一定是表示级别的事实)已经由前一个分支建立。它还可以允许编译器以一种方式简化某些表达式(特别是涉及乘法或除法的表达式),如果子表达式包含溢出,则可以提供与最初编写的求值顺序不同的结果,因为允许编译器假定溢出你给它的操作数不会发生。

为了允许优化,另一个未定义行为的大例子是别名规则。

答案 2 :(得分:4)

规范中的undefined behavior位涉及一些编译器优化。例如:

if (a > 0 && b > 0) {
    if ( a + b <= 0 ) {
       // this branch may be optimized out by compiler
    } else {
       // this branch will always run
    }
}

现代C编译器并不那么简单,它需要进行大量的猜测和优化。

答案 3 :(得分:0)

我认为你的假设1)如果我的记忆是正确的,至少在一个重要的历史架构CDC上,任何给定的处理器都可以关闭它。