这是一段简单的代码,其中出现除零。我想抓住它:
#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计算机上进行这些测试,但是想让它跨平台。
答案 0 :(得分:32)
这不是例外。这是一个错误,它在硬件级别确定并返回给操作系统,然后操作系统以某种特定于操作系统的方式通知您的程序(例如,通过查杀)过程)。
我相信在这种情况下发生的事情不是例外而是信号。如果是这种情况:操作系统会中断程序的主控制流并调用信号处理程序,这反过来会终止程序的运行。
当您取消引用空指针(然后您的程序因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在这里!
在执行信号处理程序后,系统立即终止进程并显示错误消息。
使用此方法,您可以关闭所有资源或在除以零或空指针取消引用后记录错误...但与异常不同,即使在特殊情况下也不能控制程序的流程。有效的程序不应该这样做。捕获这些信号仅对调试/诊断目的有用。
(有一些有用的信号在低级编程中非常有用,并且不会导致程序在处理程序之后被杀死,但这是一个很深的主题。) < / p>
答案 1 :(得分:13)
除以零是一个逻辑错误,程序员的错误。你不应该尝试应对它,你应该调试并消除它。此外,捕获异常是非常昂贵的 - 比分数检查更多。
您可以使用结构化异常处理来捕获除以零的错误。如何实现取决于您的编译器。 MSVC提供了一个函数来捕获结构化异常catch(...)
,还提供了将结构化异常转换为常规异常的功能,以及提供__try
/ __except
/ __finally
。但是我对MinGW不太熟悉,告诉你如何在该编译器中完成它。
答案 2 :(得分:8)
没有 语言标准的捕捉方式 来自CPU的零除。
不要过早地“优化”掉一个 科。是你的申请 真的在这种情况下受CPU限制?我怀疑它,它不是真的 如果您破坏了代码,则进行优化 否则,我可以制作你的代码 更快:
int main(int argc, char *argv[]) { /* Fastest program ever! */ }
答案 3 :(得分:6)
除以零在C ++中不是例外,请参阅https://web.archive.org/web/20121227152410/http://www.jdl.co.uk/briefings/divByZeroInCpp.html
答案 4 :(得分:3)
不知怎的,真正的解释仍然缺失。
是否可以捕获这样的异常(我理解的不是C ++异常,而是FPU异常)?
是的,您的catch
块应该适用于某些编译器。但问题是您的异常不是FPU异常。你正在进行整数除法。我不知道这是否也是一个可捕获的错误,但它不是FPU异常,它使用了浮点数的IEEE表示的特征。
答案 5 :(得分:1)
在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
答案 6 :(得分:0)
好吧,如果有关于此的异常处理,某些组件实际上需要执行检查。因此,如果您自己检查,您不会丢失任何东西。并没有比简单的比较语句更快的速度(单个CPU指令“如果等于零则跳转”或类似的东西,不记得名称)
答案 7 :(得分:0)
为了避免无限“信号8在这里!”消息,只需将'exit'添加到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;
}
答案 8 :(得分:-1)
正如其他人所说,这不是例外,它只会产生NaN或Inf。
零分割只是实现这一目标的一种方式。如果你做了很多数学计算,那就有很多的方法,比如
log(not_positive_number)
,exp(big_number)
等
如果你可以在进行计算之前检查有效的参数,那么这样做,但有时很难做到,所以你可能需要生成并处理异常。
在MSVC中,有一个包含函数#include <float.h>
的头文件_finite(x)
,它告诉数字是否有限。
我很确定MinGW有类似的东西。
您可以在计算后测试它并抛出/捕获您自己的异常或其他任何内容。