Windows on ARM浮点异常未触发问题咨询
ARM64平台Windows下浮点异常捕获失效问题分析
在Windows 11 + VS2022环境下,测试amd64与arm64系统的浮点异常捕获功能,使用以下代码:
#include <cfenv> #include <eh.h> #include <exception> #include <stdio.h> #include <windows.h> void SEFunc() { printf("About to force exception\n"); float a = 1.0f; float b = 0.0f; sscanf_s("1.0 0.0", "%f %f", &a, &b); float res1 = a / b; // trapping on amd64, not trapping on arm64 printf("%f\n", res1); } void trans_func(unsigned int, EXCEPTION_POINTERS*) { throw std::exception(); } int main(int, char**) { _set_se_translator(trans_func); unsigned int current_word = 0; unsigned int new_word = 0; _controlfp_s(¤t_word, new_word, _MCW_EM); // unmask all FP exceptions try { SEFunc(); } catch (const std::exception&) { printf("Caught an exception\n"); } }
编译命令:cl /O2 /EHa /std:c++20
问题:代码在amd64平台可正常触发trans_func并捕获除零异常,但在Snapdragon X处理器的ARM设备上仅静默输出inf。根据_controlfp_s文档说明,ARM平台应支持异常捕获,仅找到文档提及Windows因旧ARM处理器问题默认屏蔽浮点异常,咨询是操作有误还是文档未及时更新?
问题原因与解决方法
1. 编译器优化导致除法操作被消除
在/O2优化级别下,ARM64编译器会将1.0f / 0.0f这类明确的除零操作优化为编译期常量inf,跳过了实际的浮点除法指令执行,自然不会触发硬件浮点异常。
解决:
- 将参与除法的变量声明为*
volatile*,阻止编译器进行编译期优化:volatile float a = 1.0f; volatile float b = 0.0f; volatile float res1 = a / b; - 或者改用
/Od编译选项关闭所有优化,验证异常触发逻辑。
2. Windows on ARM64的系统级浮点异常屏蔽
Windows为了兼容早期不支持精确浮点异常捕获的ARM硬件,默认对所有浮点异常设置了静默处理策略——即使通过_controlfp_s解除了线程的FP控制字掩码,系统仍会拦截异常并返回inf/NaN,不会触发SEH异常。
解决:
在调用_controlfp_s之前,修改线程错误模式,允许浮点异常触发SEH:
DWORD oldErrorMode; // 清除线程错误模式中的异常屏蔽,允许浮点异常触发SEH SetThreadErrorMode(0, &oldErrorMode);
同时确保_controlfp_s的调用逻辑正确,明确解除所有浮点异常掩码:
unsigned int current_word = 0; // 0表示解除所有_MCW_EM对应的浮点异常掩码(除零、无效操作等) _controlfp_s(¤t_word, 0, _MCW_EM);
补充说明
微软文档中关于_controlfp_s支持ARM64的描述是准确的,但未明确提及Windows on ARM64的默认系统级屏蔽策略以及编译器优化的影响,这是导致测试结果差异的核心原因。
内容的提问来源于stack exchange,提问作者Ibraim Ganiev
相关产品推荐
相关产品推荐

