You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EXCEPTION_FLT_DIVIDE_BY_ZERO未抛出原因及代码修复方案

问题描述

编写三个独立函数,每个函数包含__try/__except块,预期分别抛出EXCEPTION_ACCESS_VIOLATION、EXCEPTION_INT_DIVIDE_BY_ZERO、EXCEPTION_FLT_DIVIDE_BY_ZERO异常,且每个__except配备对应过滤器。目前前两个异常可成功抛出并捕获,但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
原因分析

Windows平台下,浮点运算异常默认被CPU/FPU的控制字屏蔽,不会触发结构化异常(__try/__except捕获的是Windows结构化异常)。而整数除零、访问违例这类异常属于硬件直接触发的结构化异常,不受此屏蔽影响,因此能被正常捕获。

当执行浮点除零操作时,默认行为是生成无穷大值(INF)而非抛出结构化异常,所以__except块无法捕获到EXCEPTION_FLT_DIVIDE_BY_ZERO。

解决方法

需要通过修改浮点控制字,启用浮点除零异常的抛出,使其转化为可被__try/__except捕获的结构化异常。可以使用C标准库的_controlfp_s函数来修改控制字,解除_EM_ZERODIVIDE异常的屏蔽。

修改后的代码

在浮点除零测试函数中添加控制字设置:

#include <Windows.h>
#include <iostream>
#include <float.h> // 引入_controlfp_s的头文件

//------------------------------------------------------------------------------
// 以下两个过滤器和函数代码与原示例一致,省略重复内容
//------------------------------------------------------------------------------

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;

    // 保存原有浮点控制字,修改为启用除零异常
    unsigned int old_control_word;
    _controlfp_s(&old_control_word, 0, 0); // 获取当前控制字
    unsigned int new_control_word = old_control_word & ~_EM_ZERODIVIDE; // 解除除零异常屏蔽
    _controlfp_s(nullptr, new_control_word, _MCW_EM); // 设置新控制字

    __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";
    }

    // 恢复原有浮点控制字,避免影响后续代码
    _controlfp_s(nullptr, old_control_word, _MCW_EM);

    return r;
}

// 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

内容的提问来源于stack exchange,提问作者Alex Net

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:49:54