Question

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.

Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top