![](/img/trans.png)
[英]How to catch divide-by-zero error in Visual Studio 2008 C++?
[英]C++ : Catch a divide by zero error
这是一段简单的代码,其中发生了除以零的情况。 我试图抓住它:
#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;
}
但是应用程序无论如何都会崩溃(即使我设置了MinGW 的-fexceptions
选项)。
是否有可能捕获这样的异常(我理解这不是 C++ 异常,而是 FPU 异常)?
我知道我可以在除法之前检查除数,但我假设,因为除以零是罕见的(至少在我的应用程序中),尝试除法会更有效(如果它发生)而不是在除法之前每次测试除数。
我正在 WindowsXP 计算机上进行这些测试,但希望使其跨平台。
这也不例外。 这是在硬件级别确定的错误并返回给操作系统,然后操作系统以某种特定于操作系统的方式通知您的程序(例如,通过终止进程)。
我相信在这种情况下发生的不是例外而是信号。 如果是这种情况:操作系统会中断程序的主控制流并调用信号处理程序,后者反过来终止程序的运行。
这与您取消引用空指针时出现的错误类型相同(然后您的程序因 SIGSEGV 信号、分段错误而崩溃)。
您可以尝试使用<csignal>
标头中的函数来尝试为 SIGFPE 信号提供自定义处理程序(它用于浮点异常,但也有可能是整数除以零引发的情况 - 我真的这里不确定)。 但是,您应该注意信号处理依赖于操作系统,并且 MinGW 以某种方式“模拟”Windows 环境下的 POSIX 信号。
这是在 MinGW 4.5、Windows 7 上的测试:
#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 在这里!
在执行信号处理程序后,系统立即终止进程并显示错误消息。
使用它,您可以在除以零或空指针取消引用后关闭任何资源或记录错误……但与异常不同的是,即使在特殊情况下,这也不是控制程序流程的方法。 一个有效的程序不应该这样做。 捕获这些信号仅用于调试/诊断目的。
(有一些有用的信号通常在低级编程中非常有用,并且不会导致您的程序在处理程序之后立即被终止,但这是一个深入的主题)。
除以零是一个逻辑错误,是程序员的错误。 你不应该试图应付它,你应该调试并消除它。 此外,捕获异常的代价是极其昂贵的——比除数检查要昂贵得多。
您可以使用结构化异常处理来捕获除以零错误。 如何实现取决于您的编译器。 MSVC 提供了一个将结构化异常catch(...)
为catch(...)
的函数,还提供了一个将结构化异常转换为常规异常的__try
,并提供了__try
/ __except
/ __finally
。 但是,我对 MinGW 不够熟悉,无法告诉您如何在该编译器中执行此操作。
没有一种语言标准的方法可以从 CPU 中捕获除以零。
不要过早地“优化”掉一个分支。 在这种情况下,您的应用程序真的受CPU 限制吗? 我对此表示怀疑,如果您破坏代码,这并不是真正的优化。 否则,我可以让你的代码更快:
int main(int argc, char *argv[]) { /* Fastest program ever! */ }
不知何故,仍然缺少真正的解释。
是否有可能捕获这样的异常(我理解这不是 C++ 异常,而是 FPU 异常)?
是的,您的catch
块应该适用于某些编译器。 但问题是您的异常不是 FPU 异常。 你在做整数除法。 我不知道这是否也是一个可捕获的错误,但它不是 FPU 异常,它使用了浮点数的 IEEE 表示的功能。
在 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
为了避免无限的“信号8在这里!” 消息,只需将“退出”添加到 Kos 漂亮的代码中:
#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;
}
好吧,如果对此有异常处理,则某些组件实际上需要进行检查。 因此,如果您自己检查,您不会丢失任何东西。 没有什么比简单的比较语句更快的了(一个 CPU 指令“如果等于零则跳转”或类似的东西,不记得名字了)
正如其他人所说,这不是一个例外,它只是生成一个 NaN 或 Inf。
零除法只是一种方法。 如果你做很多数学,有很多方法,比如
log(not_positive_number)
、 exp(big_number)
等。
如果您可以在进行计算之前检查有效参数,那么就这样做,但有时这很难做到,因此您可能需要生成和处理异常。
在 MSVC 中有一个头文件#include <float.h>
包含一个函数_finite(x)
,它告诉我们一个数字是否是有限的。 我很确定 MinGW 有类似的东西。 您可以在计算后对其进行测试并抛出/捕获您自己的异常或其他任何内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.