Question

I apologize for asking a question that has been asked numerous times before. But after several searches, I realize that I may have a fundamental misunderstanding between how FPEs are to be treated in C/C++ vs. how they are treated in Fortran.

In Fortran (GNU fortran to be precise), if one wants to trap a floating point exception (use of a NAN for example), the compiler flag -ffpe-trap=invalid does the trick. The floating point exception is raised as soon as the offending statement has been executed.

In C (GNU gcc), however, this does not seem to be the case. Even more annoying (but perhaps not surprising) is that same fortran code, when called from a C main does not raise an exception (and halt execution), whereas it does when called from a Fortran main program. And this seems to be independent of whether a C or gfortran linker is used.

After much searching and reading, I see that there is C/C++ functionality available in fenv.h that suggests the "C way" of handling exceptions. I see that I can set exception flags and later check to see if exceptions have been raised. I can see how this approach might give one more flexibility over how exceptions are handled. Is this the "best practice" way of handling exceptions in C? For scientific programming (where C is often used to call fortran code) it seems inconvenient to have to have some advanced knowledge of where the exceptions might be occurring.

Is there no (straightforward) way in C to have the code that halts at the first appearance of an exception? Or is there another paradigm when it comes to exception handling in C that I am not fully grasping?

Was it helpful?

Solution 2

In the following code, I show how do do exactly what I was aiming to do with my question above. It relies on the Mac OSX extension mentioned here and the signalling value described here.

I am not an expert in either of these topics, so can make no claims as to how portable this code is. But it does do the two things I wanted : It allows me to initialise data to a "NAN", and later trap invalid use of these uninitialized values. The trap is detected by both normal execution and in gdb.

I would certainly appreciate any comments on this solution.


#include "fp_exception_glibc_extension.h"
#include <fenv.h>
#include <signal.h>
#include <stdio.h>

/*
-----------------------------------------------------------------------
This example illustrates how to initialize data with an sNAN.  Later, if
the data is used in its 'uninitialized' state, an exception is raised,
and execution halts.

The floating point exception handler 'fp_exception_glibc_extension' is
 needed for OS X portability.

 At least two blog posts were used in writing this :

 "Update: Floating-point exception handling on Mac OS X"
 http://philbull.wordpress.com/2012/12/09/update-floating-point-exception-handling-on-mac-os-x/
 Note : there is a lengthy email exchange about how portable this extension is;  see
 comments in the text of the code.

 "NaNs, Uninitialized Variables, and C++"
 http://codingcastles.blogspot.fr/2008/12/nans-in-c.html
 -----------------------------------------------------------------------
*/

void set_snan(double& f)
{
    *((long long*)&f) = 0x7ff0000000000001LL;
}

int main()
{
    /* On OS X, this extension is provided by 
       'fp_exception_glibc_extension.{c,h} */
    feenableexcept(FE_INVALID);

    double p;
    set_snan(p); /* Initialize to signaling nan */

    double q;
    q = 2*p;     /* Floating point exception is trapped here */
    printf("p = %f; q = %f\n",p,q);
}

OTHER TIPS

Since you use GNU utilities I will assume that you are on *nix. You need to enable floating point exceptions. When that is done, exceptions are delivered using signals. The following code illustrates it:

#include <fenv.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void handler(int sig) {
    printf("Floating Point Exception\n");
    exit(0);
}


int main(int argc, char ** argv) {
    feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
    signal(SIGFPE, handler);

    float a = 42.0, b = 0.0, res;

    res = a / b;

    return 0;
}

Link with libm:

gcc -o test test.c -lm

On Windows I believe you need to use a structured exception handler: http://msdn.microsoft.com/en-us/library/windows/desktop/ms680657(v=vs.85).aspx

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