C++ 为什么';t';d/=d';当d==0时抛出一个除零异常?
我不太明白为什么我没有得到零除法异常:C++ 为什么';t';d/=d';当d==0时抛出一个除零异常?,c++,compiler-optimization,undefined-behavior,division,divide-by-zero,C++,Compiler Optimization,Undefined Behavior,Division,Divide By Zero,我不太明白为什么我没有得到零除法异常: intd=0; d/=d; 我希望得到一个除零的异常,但是相反d==1 代码< d > /d=/> > d=0 < //> > < /p> < p>不可由C++标准定义整数除以零的行为。抛出异常不需要它 (浮点除零也未定义,但IEEE754对其进行了定义。) 您的编译器正在优化d/=d以有效地d=1,这是一个合理的选择。允许进行此优化,因为允许假设代码中没有未定义的行为-即d不可能为零。C++没有要捕获的“除零”异常。您观察到的行为是编译器优化的结果:
intd=0;
d/=d;
我希望得到一个除零的异常,但是相反d==1
<>代码< d > /d=/> > <代码> d=0 < //> > < /p> < p>不可由C++标准定义整数除以零的行为。抛出异常不需要它 (浮点除零也未定义,但IEEE754对其进行了定义。) 您的编译器正在优化
d/=d
以有效地d=1
,这是一个合理的选择。允许进行此优化,因为允许假设代码中没有未定义的行为-即d
不可能为零。C++没有要捕获的“除零”异常。您观察到的行为是编译器优化的结果:
- 而且,必须导致被零除的代码被认为永远不会发生
d==0
)一定不会发生d/d
必须始终等于1volatile int d = 0;
d /= d; //What happens?
所以现在的问题仍然是:既然我们已经基本上迫使编译器允许这种情况发生,那么会发生什么呢?这是未定义的行为,但我们现在阻止编译器围绕此未定义的行为进行优化
主要取决于目标环境。这不会触发软件异常,但它可以(取决于目标CPU)触发硬件异常(一个整数除以零),这不能用传统的方式捕获软件异常。对于x86CPU和大多数其他(但不是所有!)体系结构来说,情况绝对如此
但是,有一些处理硬件异常(如果发生)的方法,而不仅仅是让程序崩溃:请参阅本文,了解一些可能适用的方法:。请注意,它们因编译器而异。为了补充其他答案,被零除是未定义的行为,这一事实意味着编译器可以在发生以下情况时自由执行任何操作:
- 编译器可以假定
,并相应地进行优化。这实际上就是它在这里所做的0/0==1
- 如果编译器愿意,它还可以假设
,并将0/0==42
设置为该值d
- 编译器还可以确定
的值是不确定的,从而使变量保持未初始化状态,这样它的值将是先前写入分配给它的内存中的值。在注释中的其他编译器上观察到的一些意外值可能是由这些编译器执行类似操作引起的d
- 编译器也可能决定中止程序或在发生除零时引发异常。因为对于这个程序,编译器可以确定这种情况总是会发生,所以它可以简单地发出代码来引发异常(或完全中止执行),并将函数的其余部分视为无法访问的代码
- 编译器也可以选择停止程序并开始一个纸牌游戏,而不是在发生除零时引发异常。这也属于“未定义行为”的范畴
- 原则上,编译器甚至可以发出代码,使计算机在每次被零除时爆炸。在C++标准中没有什么可以禁止这个。(对于某些类型的应用,如导弹飞行控制器,这甚至可能被认为是一种理想的安全特性!)
- 此外,还需要修改标准,以便编译器在被零除之前也可以执行上述任何操作(或任何其他操作)。基本上,该标准允许编译器自由地重新排序操作,只要程序的可观察行为没有改变——但如果执行程序会导致未定义的行为,即使最后一个要求也会被明确放弃。因此,实际上,任何程序执行的整个行为,如果在某一点上触发未定义的行为,都是未定义的李>
- 由于上述原因,编译器还可以简单地假设未定义的行为不会发生,因为程序在某些输入上以未定义的方式运行的一个允许行为是,它的行为就像输入是其他东西一样。也就是说,即使
的原始值在编译时是未知的,编译器仍然可以假定它永远不会为零,并相应地优化代码。在OP代码的特定情况下,这实际上与编译器仅假设d
是无法区分的,但是编译器也可以假设0/0==1
中的
如果(d==0)put(“即将被零除!”);d/=d代码>永远不会执行李>put()
>P>注意,您可以通过使用Booost安全数字来在该代码中生成C++异常(以及其他情况)。p> 这是未定义的行为。没有被零除的异常。澄清一些评论:当你看到一条关于“被零除的异常”的消息时,就是操作系统告诉你出了问题。它不是C++异常。在C++中,异常由<代码>抛出语句引发。不