Gfortran提供了方便的-ffpe-trap
编译器选项,但gcc没有类似的选项。我模糊地意识到它们处理异常的方式不同,但并不足以知道为什么只要启用编译器标志就可以因FPEs而死亡,而另一个则需要包含额外的代码来开启异常。
Gfortran提供了方便的-ffpe-trap
编译器选项,但gcc没有类似的选项。我模糊地意识到它们处理异常的方式不同,但并不足以知道为什么只要启用编译器标志就可以因FPEs而死亡,而另一个则需要包含额外的代码来开启异常。
抱歉内容有点长,真正答案在底部。
浮点数异常是由C99库代码控制的,而不是由编译器标志控制。以下是一个示例:
#include <fenv.h>
#include <math.h>
#include <stdio.h>
#define PRINTEXC(ex, val) printf(#ex ": %s\n", (val & ex) ? "set" : "unset");
double foo(double a, double b) { return sin(a) / b; }
int main()
{
int e;
double x;
feclearexcept(FE_ALL_EXCEPT);
x = foo(1.2, 3.1);
e = fetestexcept(FE_ALL_EXCEPT);
PRINTEXC(FE_DIVBYZERO, e);
PRINTEXC(FE_INEXACT, e);
PRINTEXC(FE_INVALID, e);
PRINTEXC(FE_OVERFLOW, e);
PRINTEXC(FE_UNDERFLOW, e);
putchar('\n');
feclearexcept(FE_ALL_EXCEPT);
x += foo(1.2, 0.0);
e = fetestexcept(FE_ALL_EXCEPT);
PRINTEXC(FE_DIVBYZERO, e);
PRINTEXC(FE_INEXACT, e);
PRINTEXC(FE_INVALID, e);
PRINTEXC(FE_OVERFLOW, e);
PRINTEXC(FE_UNDERFLOW, e);
return lrint(x);
}
输出:
FE_DIVBYZERO: unset
FE_INEXACT: set
FE_INVALID: unset
FE_OVERFLOW: unset
FE_UNDERFLOW: unset
FE_DIVBYZERO: set
FE_INEXACT: set
FE_INVALID: unset
FE_OVERFLOW: unset
FE_UNDERFLOW: unset
#pragma STDC FENV_ACCESS on
#define _GNU_SOURCE
#include <fenv.h>
int main()
{
#ifdef FE_NOMASK_ENV
fesetenv(FE_NOMASK_ENV);
#endif
// ...
}
然而,当接收到 SIGFPE 信号时,不太清楚该做什么,因为无法撤销错误指令。 (请参见 @EricPostpischil 的关于 pragma 的评论;谢谢!)
#pragma STDC FENV_ACCESS on
通知实现。否则,其行为在 C 标准中是未定义的。 - Eric Postpischilfeenableexcept
жҲ–fsetenv
иҖҢдёҚжҳҜеҸӘз”Ёзј–иҜ‘еҷЁж Үеҝ—пјҹ - bwkeller