捕获浮点异常的方法取决于体系结构。这是我在 Intel (x86) Mac 上成功测试的代码:它两次取负数的平方根,一次在之前,一次在之后,从而启用浮点异常捕获。第二次,fpe_signal_handler()
叫做。
#include <cmath> // for sqrt()
#include <csignal> // for signal()
#include <iostream>
#include <xmmintrin.h> // for _mm_setcsr
void fpe_signal_handler(int /*signal*/) {
std::cerr << "Floating point exception!\n";
exit(1);
}
void enable_floating_point_exceptions() {
_mm_setcsr(_MM_MASK_MASK & ~_MM_MASK_INVALID);
signal(SIGFPE, fpe_signal_handler);
}
int main() {
const double x{-1.0};
std::cout << sqrt(x) << "\n";
enable_floating_point_exceptions();
std::cout << sqrt(x) << "\n";
}
使用Xcode提供的apple-clang编译器进行编译
clang++ -g -std=c++17 -o fpe fpe.cpp
并运行给出以下预期输出:
nan
Floating point exception!
我想编写一个类似的程序,在 M1 (arm64) Mac 上执行与上述程序相同的操作。我尝试了以下方法:
#include <cfenv> // for std::fenv_t
#include <cmath> // for sqrt()
#include <csignal> // for signal()
#include <fenv.h> // for fegetenv(), fesetenv()
#include <iostream>
void fpe_signal_handler(int /*signal*/) {
std::cerr << "Floating point exception!\n";
exit(1);
}
void enable_floating_point_exceptions() {
std::fenv_t env;
fegetenv(&env);
env.__fpcr = env.__fpcr | __fpcr_trap_invalid;
fesetenv(&env);
signal(SIGFPE, fpe_signal_handler);
}
int main() {
const double x{-1.0};
std::cout << sqrt(x) << "\n";
enable_floating_point_exceptions();
std::cout << sqrt(x) << "\n";
}
它几乎可以工作:使用 Xcode 提供的 apple-clang 编译器编译后
clang++ -g -std=c++17 -o fpe fpe.cpp
我得到以下输出:
nan
zsh: illegal hardware instruction ./fpe
我尝试添加-fexceptions
标志,但这没有什么区别。我注意到ARM 编译器工具链“不支持 AArch64 目标的浮点异常捕获”,但我不确定这是否适用于带有 Apple 工具链的 M1 Mac。
我是否正确地认为 M1 Mac 硬件不支持浮点异常捕获?或者有没有办法修改这个程序,使其捕获第二个浮点异常,然后调用fpe_signal_handler()
?
使用 ISO C 在同一线程内同步测试异常确实可以正常工作fetestexcept
from <fenv.h>
as in cppreference 示例。这里的问题是让 FP 异常真正捕获,以便操作系统提供SIGFPE
,而不是仅仅在 FP 环境中设置粘性标志。