【问题标题】:Catch Floating Point Exceptions using a compiler option with C [closed]使用 C 的编译器选项捕获浮点异常 [关闭]
【发布时间】:2013-09-05 19:14:02
【问题描述】:

Gfortran 有方便的-ffpe-trap 编译器选项,但没有类似的选项可用于gcc。我隐约知道他们处理异常的方式不同,但不足以知道为什么一个人可以通过启用编译器标志死于FPEs,但另一个需要包含额外的代码来打开异常。

【问题讨论】:

  • 注意,在 Fortran 2003 中,使用 IEEE 异常和舍入模式可以做很多类似于 C 中的事情。 gfortran 还不支持。如果编译器标志用于捕获异常,它可能会干扰这样的代码。

标签: c floating-point fortran scientific-computing


【解决方案1】:

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

浮点异常由 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

更新:使用 GNU GCC,您也许可以使用浮点异常来捕获并发送信号:

#pragma STDC FENV_ACCESS on

#define _GNU_SOURCE
#include <fenv.h>

int main()
{
#ifdef FE_NOMASK_ENV
    fesetenv(FE_NOMASK_ENV);
#endif

    // ...
}

但是,当您收到 SIGFPE 时您应该做什么并不完全清楚,因为您无法撤消错误的指令。 (请参阅@EricPostpischil 的关于编译指示的 cmets;谢谢!)

【讨论】:

  • 我认为这不能以任何方式回答 OP 的问题。 OP 在问 为什么 gfortran 有 FPE 标志而 gcc 没有,而不是 如何 在 C 中标记 FPE。
  • @KyleKanos:你是对的。我不完全确定我在寻找什么,但现在我找到了。已更新。
  • 访问浮点环境或在非默认浮点控制模式下运行的代码必须使用#pragma STDC FENV_ACCESS on 通知实现。否则,C 标准未定义该行为。
  • @KerrekSB:C 2011 (N1570) 7.6.1,它也在 C 1999 中。实际上,如果 pragma 缺失,说行为未定义是过于强烈的。默认 FENV_ACCESS 状态是实现定义的。如果实现将其定义为“关闭”并且缺少 pragma,则标准未定义行为。如果我没记错的话,GCC 有一段时间不支持 pragma。
  • @KyleKanos 说得比我好:为什么我需要使用feenableexceptfsetenv 而不仅仅是编译器标志?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多