【问题标题】:Integer division by zero exception isn't caught整数除以零异常未被捕获
【发布时间】:2014-12-06 13:08:46
【问题描述】:

我一直在阅读Teach Yourself C++ In 21 Days , by Jesse Liberty一书,遇到了Exceptions and Errors一章。作者使用了这个例子:

int top = 10;
int bottom = 0;
try
{
    cout << "top divided by bottom = ";
    cout << (top / bottom) << endl;
}
catch(...)
{
    cout << "something has gone wrong!" << endl;
}

这对他来说很好用。异常被捕获,输出为:

top divided by bottom = something has gone wrong!

我自己试了一下,收到如下错误:

Unhandled exception at 0x0124152d in stuff.exe: 0xC0000094: Integer division by zero.

根据this thread,“整数除以零在标准 C++ 中也不例外。”但是 Visual Studio 显然在这里抛出了一个异常,虽然没有捕捉到它。

我尝试将topbottom 定义为double,我收到以下输出:

top divided by bottom = 1.#INF

那么为什么try catch 块没有捕获integer division by zero 异常?

【问题讨论】:

  • 这太糟糕了。这是未定义的行为(这不是 C++ 异常)。我知道这本书很糟糕,但这太荒谬了。
  • 这并不能激发人们对那本书的信心。
  • Windows 异常和 C++ 异常是非常不同的野兽。我建议烧掉那本书和getting a better one。不要只是把它扔掉 - 其他人可能会捡起它。
  • trycatch 仅用于 C++ 异常而不是 CPU 异常,它们是两个正交的概念,尽管名称相似,但完全不同。
  • 应该有一本书叫《21年自学C++》。

标签: visual-c++ exception-handling seh


【解决方案1】:

Use /EHa to switch the exception-handling model,所以非C++异常可以被try-catch捕获。

请注意,如果您这样做,所有异步异常都将转换为同步异常,而您真的不想捕获大多数。
因此,不推荐用于一般代码

顺便说一句,盲目地捕捉所有你能做到的东西是一种已知的反模式,只捕捉你真正期望和能够处理的东西。

查看这里__try-__except,它总是可以捕获异步异常:http://msdn.microsoft.com/en-us/library/s58ftw19.aspx

【讨论】:

  • 如果我错了,请纠正我,但我相信 MSVC 的 __try__catch 也能得到这些。
  • @chris IIRC 这是__except
  • 当然不是。只是编译器开关的替代品。哎呀,如果我什至不记得正确的标识符,我就不会使用它们。
  • 顺便说一句,从C#中我发现异常错误处理模型非常有效。尤其是要使用它,您必须抓住一切。它看起来像这样:假设您有一个类与网络一起使用,而更高的类与网络、串行等接口一起使用。这些类不关心错误,所有处理都完成得更高.这里可能真的有很多例外:你想手工写这些吗?最后,所有这些都会导致出现错误消息并关闭程序。不过,那些不是你可以单独写的。
  • @Hi-Angel:“不可能的状态”是您作为程序员推断程序永远无法达到的任何状态,因此您理所当然地放弃了进一步考虑。它们通常是由于逻辑推理中的致命缺陷、偶尔的判断失误、子模块违反合同、底层平台崩溃以及来自上方的恶意干扰而发生的。处理得当的信号都不是这些。此外,它们都不受本机代码的限制,它们也可以发生在“安全”的托管代码中。
【解决方案2】:

这本书可能忽略了告诉你必须使用 /EHa 进行编译。默认是/EHsc,它不会导致这些SEH异常被catch(...)捕获。

有 catch (...) catch everything 不是很漂亮。你不希望这种情况发生:

int* p = 0;
try {
    int result = *p / 0;
    std::cout << result << std::endl;
}
catch (...) {
    std::cout << "Division by zero" << std::endl;
}

实际上不是零故障除法,当然不好。更好的鼠标陷阱是将 SEH 异常转换为 C++ 异常。您可以通过安装一个在发生 SEH 异常时运行的回调来做到这一点,如下所示:

#include <exception>
#include <eh.h>
#include <iostream>

class divisionbyzero_exception : public std::runtime_error {
public:
    divisionbyzero_exception() : std::runtime_error("Division by zero") {}
};

void translate_seh_exception(unsigned int exceptioncode, struct _EXCEPTION_POINTERS* pExp) {
    if (exceptioncode == 0xc0000094) throw divisionbyzero_exception();
}

int main(int argc, char* argv[])
{
    _set_se_translator(translate_seh_exception);
    try {
        int result = argc / 0;
        std::cout << result << std::endl;
    }
    catch (divisionbyzero_exception& ex) {
        std::cout << ex.what() << std::endl;
    }
    return 0;
}

请记住,这是完全不可移植的。

【讨论】:

猜你喜欢
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多