0

在编译器MSVC、GCC、Clang或它们的通用包装器中是否有通用解决方案来捕获异常,例如除以零、分段错误等,可能在“boost”库中?

当然必须是基于每个编译器细微差别的通用解决方案。即使我确实在每个编译器下编写了类似的解决方案,我仍然可以忽略任何细微差别。例如,我可以在带有 SEH 异常的 MSVC 中编写并使用密钥编译它:/ZHa

#include<iostream>
#include<string>

#ifdef _MSC_VER
#include <windows.h>
#include <eh.h>


class SE_Exception
{
private:
    EXCEPTION_RECORD m_er; 
    CONTEXT m_context; 
    unsigned int m_error_code;
public:
    SE_Exception(unsigned int u, PEXCEPTION_POINTERS pep) 
    {
        m_error_code = u;
        m_er = *pep->ExceptionRecord; 
        m_context = *pep->ContextRecord;
    }
    ~SE_Exception() {}
    unsigned int get_error_code() const { return m_error_code; }
    std::string get_error_str() const {
        switch(m_error_code) {
        case EXCEPTION_INT_DIVIDE_BY_ZERO: return std::string("INT DIVIDE BY ZERO");
        case EXCEPTION_INT_OVERFLOW:    return std::string("INT OVERFLOW");
        // And other 20 cases!!!

        }
        return std::string("UNKNOWN");
    }
};

void trans_func(unsigned int u, EXCEPTION_POINTERS* pExp)
{
    throw SE_Exception(u, pExp);
}

#else

struct SE_Exception
{
    unsigned int get_error_code() const { return 0; }
    std::string get_error_str() const { return std::string("Not MSVC compiler"); }
};
#endif

int main() {
#ifdef _MSC_VER
    _set_se_translator( trans_func );
#endif

    try {
        int a = 0;
        int b = 1 / a;
        std::cout << "b: " << b << std::endl;
    } catch(SE_Exception &e) {
        std::cout << "SEH exception: (" << e.get_error_code() << ") " << e.get_error_str() << std::endl;        
    } catch(...) {
        std::cout << "Unknown exception." << std::endl;        
    }

    int b;
    std::cin >> b;
    return 0;
}
4

1 回答 1

1

除以零和许多其他特定的、与硬件相关的运行时错误(例如无效的指针取消引用)是未定义的行为,这意味着实现可以自由地以它想要的任何方式处理它。

特别是除以零、溢出和其他数学错误,请参阅(强调我的):

5/4 [expr]

如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。[注意:大多数现有的 C++ 实现忽略整数溢出。除以零的处理,使用零除数形成余数,所有浮点异常因机器而异,通常可以通过库函数进行调整。——尾注]

5.6/4 [expr.mul]

二元 / 运算符产生商,二元 % 运算符产生第一个表达式除以第二个表达式的余数。如果 / 或 % 的第二个操作数为零,则行为未定义。

关于空指针取消引用,请参见:

8.3.2/5 [dcl.ref]

特别是,在定义良好的程序中不能存在空引用,因为创建此类引用的唯一方法是将其绑定到通过取消引用空指针获得的“对象”,这会导致未定义的行为

其他特定错误散布在整个标准中,我不会全部引用它们,但你明白了。


既然是UB,就没有万能的办法来处理。通常,MS Windows 将通过 SEH 传播错误,类 Unix 平台将使用信号,其他操作系统甚至可能执行其他操作。正如上面引用中所指出的,甚至可以通过依赖于实现的库调用来调整行为。

唯一真正的解决方案是首先通过在代码中插入相关检查来防止这些错误的发生。

于 2013-06-14T11:03:59.937 回答