C++ EXCEPTION_FLT_DIVIDE_BY_ZERO 硬件异常未捕获

问题描述 投票:0回答:1

我有三个专用函数,每个函数都包含一个

__try/_except
块,并且应分别抛出
EXCEPTION_ACCESS_VIOLATION
EXCEPTION_INT_DIVIDE_BY_ZERO
EXCEPTION_FLT_DIVIDE_BY_ZERO
异常。还为每个
__except
提供了一个过滤器。

EXCEPTION_ACCESS_VIOLATION
EXCEPTION_INT_DIVIDE_BY_ZERO
异常被抛出并成功捕获。

EXCEPTION_FLT_DIVIDE_BY_ZERO
不会抛出异常。为什么?

如何修复代码以捕获异常?

#include <Windows.h>
#include <iostream>

//------------------------------------------------------------------------------
int filter_access_violation(unsigned int code, EXCEPTION_POINTERS* xp)
{
    if( code == EXCEPTION_ACCESS_VIOLATION )
    {
        std::cout << "OK: filter EXCEPTION_ACCESS_VIOLATION\n";
        return EXCEPTION_EXECUTE_HANDLER;
    }
    std::cout << "Error: filter EXCEPTION_ACCESS_VIOLATION\n";
    return EXCEPTION_CONTINUE_SEARCH;
}

void access_violation(int* pt)
{
    std::cout << "\nTesting: EXCEPTION_ACCESS_VIOLATION\n";
    __try
    {
        *pt = 1;
        std::cout << "Error: EXCEPTION_ACCESS_VIOLATION not thrown\n";
    }
    __except (filter_access_violation(GetExceptionCode(), GetExceptionInformation()))
    {
        std::cout << "OK: __except EXCEPTION_ACCESS_VIOLATION\n";
    }
}

//------------------------------------------------------------------------------
int filter_int_divide_by_zero(unsigned int code, EXCEPTION_POINTERS* xp)
{
    if (code == EXCEPTION_INT_DIVIDE_BY_ZERO)
    {
        std::cout << "OK: filter EXCEPTION_INT_DIVIDE_BY_ZERO\n";
        return EXCEPTION_EXECUTE_HANDLER;
    }
    std::cout << "Error: filter EXCEPTION_INT_DIVIDE_BY_ZERO\n";
    return EXCEPTION_CONTINUE_SEARCH;
}

int int_divide_by_zero(int divisor)
{
    std::cout << "\nTesting: EXCEPTION_INT_DIVIDE_BY_ZERO\n";
    auto r = 1;
    __try
    {
        r = 1 / divisor;
        std::cout << "Error: EXCEPTION_INT_DIVIDE_BY_ZERO not thrown\n";
    }
    __except (filter_int_divide_by_zero(GetExceptionCode(), GetExceptionInformation()))
    {
        std::cout << "OK: __except EXCEPTION_INT_DIVIDE_BY_ZERO\n";
    }
    return r;
}

//------------------------------------------------------------------------------
int filter_float_divide_by_zero(unsigned int code, EXCEPTION_POINTERS* xp)
{
    if (code == EXCEPTION_FLT_DIVIDE_BY_ZERO)
    {
        std::cout << "OK: filter EXCEPTION_FLT_DIVIDE_BY_ZERO\n";
        return EXCEPTION_EXECUTE_HANDLER;
    }
    std::cout << "Error: filter EXCEPTION_FLT_DIVIDE_BY_ZERO\n";
    return EXCEPTION_CONTINUE_SEARCH;
}

float float_divide_by_zero(float divisor)
{
    std::cout << "\nTesting: EXCEPTION_FLT_DIVIDE_BY_ZERO\n";
    auto r = 1.0f;
    __try
    {
       r  = 1.0f / divisor;
       std::cout << "Error: EXCEPTION_FLT_DIVIDE_BY_ZERO not thrown\n";
    }
    __except( filter_float_divide_by_zero(GetExceptionCode(), GetExceptionInformation()) )
    {
        std::cout << "OK: __except EXCEPTION_FLT_DIVIDE_BY_ZERO\n";
    }
    return r;
}

int main()
{
    access_violation(nullptr);
    int_divide_by_zero(0);
    float_divide_by_zero(0);
}

输出:

Testing: EXCEPTION_ACCESS_VIOLATION
OK: filter EXCEPTION_ACCESS_VIOLATION
OK: __except EXCEPTION_ACCESS_VIOLATION

Testing: EXCEPTION_INT_DIVIDE_BY_ZERO
OK: filter EXCEPTION_INT_DIVIDE_BY_ZERO
OK: __except EXCEPTION_INT_DIVIDE_BY_ZERO

Testing: EXCEPTION_FLT_DIVIDE_BY_ZERO
Error: EXCEPTION_FLT_DIVIDE_BY_ZERO not thrown
c++ windows exception visual-c++ try-except
1个回答
0
投票

默认情况下,对于MSVC编译并在Windows上运行的C或C++程序, 浮点除以零不会引发操作系统异常(也不会引发操作系统异常) C++ 中的语言级异常)。

为了引起浮点除以零来引发操作系统 异常,调用 MSVC 特定的

_controlfp
功能如下:

_controlfp(0 /*new value*/, _EM_ZERODIVIDE /*mask of bits to change*/);

浮点行为由 32 位控制字控制, 可以使用

_controlfp
进行更改。 上面的调用设置了
_EM_ZERODIVIDE
标志为零。

异常掩码(EM)是控制字的一部分,它指定 哪些操作会引发异常。 当设置一个位时,该条件 是“屏蔽”的,意味着“不”引发异常。 清除该位 启用相应的异常。 注意这里“面具”一词的两种不同含义:一个是 浮点控制字的一部分表示“不”要引发什么, 而另一个是

_controlfp

API 的一个元素,说明 to 的内容 改变。

如果将上面这行代码作为 main() 的第一行插入
问题中的代码,那么修改后的程序的输出是:

Testing: EXCEPTION_ACCESS_VIOLATION OK: filter EXCEPTION_ACCESS_VIOLATION OK: __except EXCEPTION_ACCESS_VIOLATION Testing: EXCEPTION_INT_DIVIDE_BY_ZERO OK: filter EXCEPTION_INT_DIVIDE_BY_ZERO OK: __except EXCEPTION_INT_DIVIDE_BY_ZERO Testing: EXCEPTION_FLT_DIVIDE_BY_ZERO OK: filter EXCEPTION_FLT_DIVIDE_BY_ZERO OK: __except EXCEPTION_FLT_DIVIDE_BY_ZERO <--- what we wanted

为了完整起见,我会注意到上面链接的文档说:
应包括 

<float.h>
,尽管出现了包括 
<windows.h>

足够了。

文档还说要添加:
#pragma fenv_access (on)

但是,在我的测试中,我没有观察到省略它有任何区别 并包括它。

便携性考虑

在大多数平台上,相当于 GCC 的

_controlfp

feenableexcept

。
但是,当使用 MinGW 编译时,请使用 _controlfp
,如上所示。
不幸的是,
C99标准浮点环境API

<fenv.h>

中声明的不包括任何方式影响 操作会导致操作系统陷阱。


© www.soinside.com 2019 - 2024. All rights reserved.