val*_*kov 80 c++ division divide-by-zero compiler-optimization undefined-behavior
我不太明白为什么我不能除以零例外:
int d = 0;
d /= d;
Run Code Online (Sandbox Code Playgroud)
我本来希望得到除以零的除法运算,但是反而d == 1
。
为什么在什么时候不d /= d
将被零除d == 0
?
Xir*_*ema 106
C ++没有要捕获的“零除”异常。您观察到的行为是编译器优化的结果:
d == 0
)中未定义行为的条件一定不会发生d / d
必须始终等于1。我们可以强制编译器以较小的代码调整来触发被零除的“实数”除法。
volatile int d = 0;
d /= d; //What happens?
Run Code Online (Sandbox Code Playgroud)
所以现在问题仍然存在:既然我们基本上已经迫使编译器允许这种情况发生了,那会发生什么?这是未定义的行为-但是我们现在阻止编译器针对此未定义的行为进行优化。
通常,它取决于目标环境。这不会触发软件异常,但是可以(取决于目标CPU)触发硬件异常(零整数分割),无法以传统方式捕获软件异常。对于x86 CPU和大多数其他(但不是全部!)架构,绝对是这种情况。
但是,有一些方法可以处理硬件异常(如果发生),而不仅仅是让程序崩溃:在这篇文章中查找一些可能适用的方法:捕获异常:除以零。请注意,它们因编译器而异。
Ilm*_*nen 36
为了补充其他答案,除以零是未定义的行为,这意味着编译器可以在发生任何情况的情况下自由执行任何操作:
0 / 0 == 1
并相应地进行优化。这实际上是这里所做的。0 / 0 == 42
并将其设置d
为该值。d
不确定,从而使变量保持未初始化状态,以便其值将等于先前写入为其分配的内存中的任何值。注释中在其他编译器上观察到的一些意外值可能是由那些编译器执行此类操作引起的。d
在编译时不知道的原始值,编译器仍可以假定它永远不会为零,并相应地优化代码。在OP代码的特定情况下,仅假设,这与编译器实际上是无法区分的0 / 0 == 1
,但是例如,编译器也可以假设puts()
in if (d == 0) puts("About to divide by zero!"); d /= d;
永远不会执行!Bat*_*eba 28
C ++标准未定义整数除以零的行为。这是不是需要抛出异常。
(浮点除以零也未定义,但IEEE754对其进行了定义。)
您的编译器正在d /= d
有效地d = 1
进行优化,这是一个合理的选择。可以进行此优化,因为可以假定代码中没有未定义的行为- d
不可能为零。