整数溢出和未定义的行为

rus*_*lik 14 c

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

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

我可以想到两个原因:

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

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

那么,为什么有人会避免造成它呢?我错过了什么吗?

R..*_*R.. 12

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

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

  • 德国歇斯底里的葡萄干 (3认同)

Pau*_*l R 11

虽然大多数现代CPU使用2的补码,并且整数溢出导致可预测的模数环绕,但这绝不是通用的 - 为了保持语言足够通用以便可以在最广泛的体系结构上使用,最好指定整数溢出是UB .


J-1*_*DiZ 5

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
    }
}
Run Code Online (Sandbox Code Playgroud)

现代 C 编译器并没有那么简单,它做了很多猜测和优化。

  • 这不是 `volatile` 关键字的有效使用。如果它有效,则是特定实现的结果,而不是特定行为。即它仍然是未定义的行为。 (4认同)