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不太了解,告诉你如何在编译器中做到这一点。
-
从CPU中获取被零除的语言标准的方法是没有的。
-
不要过早地“优化”一个分支。 在这种情况下,你的应用程序真的是 CPU绑定的吗? 我怀疑它,如果你破坏你的代码,这不是一个真正的优化。 否则,我可以让你的代码更快:
int main(int argc, char *argv[]) { /* Fastest program ever! */ }
除以零在C ++中不是例外,请参阅https://web.archive.org/web/20121227152410/http://www.jdl.co.uk/briefings/divByZeroInCpp.html
不知怎的,真正的解释仍然是缺失的。
是否有可能捕捉到这样的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或其他。