C ++:通过零错误捕获除法

这是一个简单的一段代码,其中除零发生。 我试图抓住它:

#include <iostream> int main(int argc, char *argv[]) { int Dividend = 10; int Divisor = 0; try { std::cout << Dividend / Divisor; } catch(...) { std::cout << "Error."; } return 0; } 

但无论如何,应用程序崩溃(即使我把选项-fexceptions MinGW )。

是否有可能捕捉到这样的exception(我知道这不是一个C ++exception,而是一个FPUexception)?

我知道我可以分割之前检查除数,但是我做了这样的假设,因为除零(很less在我的应用程序中)是很less见的,所以尝试分割(并捕获错误if它发生)比每次除数之前testing除数。

我正在WindowsXP计算机上进行这些testing,但希望使其跨平台。

这不是一个例外。 这是一个在硬件级别确定的错误 ,并返回到操作系统,然后操作系统以某种特定于操作系统的方式通知您的程序(例如通过终止进程)。

相信在这种情况下,发生的事情不是一个例外,而是一个信号。 如果是这样的话:操作系统会中断程序的主控制stream程,并调用一个信号处理程序,从而终止程序的运行。

这是当你解引用一个空指针(然后你的程序因SIGSEGV信号崩溃,分段错误)而出现的相同types的错误。

您可以尝试使用<csignal>头文件中的函数来尝试为SIGFPE信号提供一个自定义处理程序(这是针对浮点exception的,但也可能是由零整数除法引起的 – 我真的不确定)。 但是你应该注意到信号处理是依赖于操作系统的,MinGW在Windows环境下以某种方式“模拟”了POSIX信号。


这是对MinGW 4.5,Windows 7的testing:

 #include <csignal> #include <iostream> using namespace std; void handler(int a) { cout << "Signal " << a << " here!" << endl; } int main() { signal(SIGFPE, handler); int a = 1/0; } 

输出:

信号8在这里!

执行完信号处理程序后,系统将终止进程并显示错误消息。

使用这种方法,您可以closures任何资源,或者在被零除或空指针解引用之后logging错误…但与例外情况不同的是,即使在特殊情况下,也不是控制程序stream的方法。 有效的程序不应该这样做。 捕获这些信号仅用于debugging/诊断目的。

(有一些有用的信号在低级编程中是非常有用的,不会导致你的程序在处理程序后立即被杀死,但这是一个很深的话题)。

除以零是一个逻辑错误,是程序员的一个错误。 你不应该试图应付它,你应该debugging和消除它。 另外,捕获exception是非常昂贵的,而不仅仅是除数检查。

您可以使用结构化exception处理来捕获除以零的错误。 如何实现取决于你的编译器。 MSVC提供了将结构化exceptioncatch(...)catch(...)的function,并提供了将结构化exception转换为常规exception以及提供__try / __except / __finally 。 不过,我对MinGW不太了解,告诉你如何在编译器中做到这一点。

  1. 从CPU中获取被零除的语言标准的方法是没有的。

  2. 不要过早地“优化”一个分支。 在这种情况下,你的应用程序真的是 CPU绑定的吗? 我怀疑它,如果你破坏你的代码,这不是一个真正的优化。 否则,我可以让你的代码更快:

     int main(int argc, char *argv[]) { /* Fastest program ever! */ } 

不知怎的,真正的解释仍然是缺失的。

是否有可能捕捉到这样的exception(我知道这不是一个C ++exception,而是一个FPUexception)?

是的,你的catch块应该在一些编译器上工作。 但问题是你的exception不是一个FPUexception 。 你正在做整数除法。 我不知道这是否也是一个可捕获的错误,但它不是一个FPUexception,它使用浮点数的IEEE表示function。

在Windows上(使用Visual C ++),试试这个:

 BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult) { __try { *pResult = dividend / divisor; } __except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return FALSE; } return TRUE; } 

MSDN: http : //msdn.microsoft.com/en-us/library/ms681409( v= vs.85).aspx

那么,如果有一个exception处理这个,一些组件实际上需要做检查。 因此,如果您自己检查,则不会丢失任何东西。 并没有比简单的比较语句更快的速度(一个单一的CPU指令“跳转,如果等于零”或类似的东西,不记得名字)

为了避免无限的“信号8在这里!” 消息,只需添加“退出”科斯不错的代码:

 #include <csignal> #include <iostream> #include <cstdlib> // exit using namespace std; void handler(int a) { cout << "Signal " << a << " here!" << endl; exit(1); } int main() { signal(SIGFPE, handler); int a = 1/0; } 

正如其他人所说,这不是一个例外,它只是产生一个NaN或Inf。

零分只是一个方法。 如果你做了很多math,有很多方法,比如说
log(not_positive_number)exp(big_number)

如果在计算之前可以检查有效的参数,那么这样做,但有时很难做到,所以您可能需要生成和处理exception。

在MSVC中有一个包含函数_finite(x)的头文件#include <float.h> ,它告诉数字是否是有限的。 我很确定MinGW有类似的东西。 你可以在计算后testing它,并抛出/捕获你自己的exception或其他。