在不同的C ++中存在通用解决方案 - 编译器将异常类型除以零,seg-fault?

时间:2013-06-14 10:30:13

标签: c++ visual-c++ gcc clang

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

当然必须是基于每个编译器的细微差别的通用解决方案。 即使我在每个编译器下都写了类似的解决方案,我仍然可以离开并忘记任何细微差别。 例如,我可以使用SEH-exceptions在MSVC中编写,并使用key:/ 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;
}

1 个答案:

答案 0 :(得分:1)

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

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

  

5/4 [expr]

     

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

     

5.6 / 4 [expr.mul]

     

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

关于空指针解除引用,请参阅:

  

8.3.2 / 5 [dcl.ref]

     

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

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


由于它是UB,没有通用的解决方案来处理它。通常,MS Windows将通过SEH传播错误,类Unix的平台将使用信号,而其他操作系统甚至可以做其他事情。如上面引用中所述,甚至可以通过依赖于实现的库调用来调整行为。

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