使用C编译器选项捕捉浮点异常 [英] Catch Floating Point Exceptions using a compiler option with C

查看:302
本文介绍了使用C编译器选项捕捉浮点异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

解决方案

对不起,真正的答案是在底部。



浮点异常由C99库代码控制,而不是由编译器标志控制。下面是一个例子:

  #include< fenv.h> 
#include< math.h>
#include< stdio.h>
$ b #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('\\\
');

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);

$ / code $ / pre
$ b $输出:

  FE_DIVBYZERO:取消设置
FE_INEXACT:设置
FE_INVALID:取消设置
FE_OVERFLOW:取消设置
FE_UNDERFLOW:取消设置

FE_DIVBYZERO:set
FE_INEXACT:set
FE_INVALID:unset
FE_OVERFLOW:未设定
FE_UNDERFLOW:未设定
更新:使用GNU GCC,您可能会导致浮点异常陷阱和发送信号:pre





  #pragma STDC FENV_ACCESS on 

#define _GNU_SOURCE
#include
int main()
{
#ifdef FE_NOMASK_ENV
fesetenv(FE_NOMASK_ENV);
#endif

// ...
}



然而,当你收到一个SIGFPE时,你不应该做什么,因为你不能撤销错误的指令。 (请参阅@ EricPostpischil关于该附注的评论,谢谢!)

Gfortran has the handy -ffpe-trap compiler option, but no similar option is available for gcc. I am vaguely aware that they handle exceptions differently, but not enough to know why one can die from FPEs just by enabling a compiler flag, but the other requires including extra code to turn exceptions on.

解决方案

Sorry for the wall of text; the real answer is at the bottom.

Floating point exceptions are controlled by library code in C99, not by compiler flags. Here's an example:

#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);
}

Output:

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


Update: With GNU GCC, you may be able to alternatively cause floating point exceptions to trap and send a signal:

#pragma STDC FENV_ACCESS on

#define _GNU_SOURCE
#include <fenv.h>

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

    // ...
}

However, it's not entirely clear what you should do when you receive a SIGFPE, since you can't undo the faulty instruction. (And see @EricPostpischil's comments about the pragma; thanks!)

这篇关于使用C编译器选项捕捉浮点异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆