使用带有C的编译器选项捕获浮点exception

Gfortran有一个方便的-ffpe-trap编译器选项,但gcc没有类似的选项。 我隐约意识到他们以不同的方式处理exception,但还不足以知道为什么只能通过启用编译器标志来死于FPE ,而另一个则需要包含额外的代码来启用exception。

对不起文字的墙; 真正的答案在底部。

浮点exception由C99中的库代码控制,而不是由编译器标志控制。 这是一个例子:

 #include  #include  #include  #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 

更新:使用GNU GCC,您可能会导致浮点exception陷阱并发送信号:

 #pragma STDC FENV_ACCESS on #define _GNU_SOURCE #include  int main() { #ifdef FE_NOMASK_ENV fesetenv(FE_NOMASK_ENV); #endif // ... } 

但是,当您收到SIGFPE时,您应该做什么并不完全清楚,因为您无法撤消故障指令。 (并查看@ EricPostpischil对该pragma的评论;谢谢!)