使用C编译器选项捕捉浮点异常

3

Gfortran提供了方便的-ffpe-trap编译器选项,但gcc没有类似的选项。我模糊地意识到它们处理异常的方式不同,但并不足以知道为什么只要启用编译器标志就可以因FPEs而死亡,而另一个则需要包含额外的代码来开启异常。


请注意,在Fortran 2003中,可以使用IEEE异常和舍入模式来执行许多类似于C语言的操作。尽管gfortran尚不支持此功能。如果使用编译器标志来捕获异常,可能会干扰这样的代码。 - Vladimir F Героям слава
1个回答

3

抱歉内容有点长,真正答案在底部。

浮点数异常是由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 的关于 pragma 的评论;谢谢!)


2
我认为这并没有以任何方式回答OP的问题。OP问的是为什么gfortran有一个FPE标志而gcc没有,而不是如何在C中标记FPE。 - Kyle Kanos
1
访问浮点环境或在非默认浮点控制模式下运行的代码必须使用 #pragma STDC FENV_ACCESS on 通知实现。否则,其行为在 C 标准中是未定义的。 - Eric Postpischil
1
@KerrekSB:C 2011(N1570)7.6.1,而且在C 1999中也有。实际上,如果缺少#pragma,则说行为未定义太过强硬。默认的FENV_ACCESS状态是实现定义的。如果实现将其定义为“关闭”,并且缺少#pragma,则行为按标准未定义。如果我没记错的话,GCC一段时间内不支持#pragma。 - Eric Postpischil
1
@KyleKanosиҜҙеҫ—жҜ”жҲ‘еҘҪпјҡдёәд»Җд№ҲжҲ‘йңҖиҰҒдҪҝз”ЁfeenableexceptжҲ–fsetenvиҖҢдёҚжҳҜеҸӘз”Ёзј–иҜ‘еҷЁж Үеҝ—пјҹ - bwkeller
@KerrekSB 太棒了,这就是我的答案。非常感谢! - bwkeller
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接