3

Gfortranには便利なコンパイラ オプションがありますが、 gcc-ffpe-trapには同様のオプションがありません。例外の処理方法が異なることは漠然と認識していますが、コンパイラ フラグを有効にするだけでFPEが原因で停止する理由を知るには十分ではありません。

4

1 に答える 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 のコメントを参照してください。ありがとう!)

于 2013-09-05T19:52:48.950 に答える