How to Trap Floating-Point Exceptions Using C++

ID: Q106261


The information in this article applies to:


SUMMARY

In C++, exceptions are normally handled by try catch blocks. However, Microsoft C++ versions 7.0 and 8.0 do not support the handling of floating-point exceptions. Also, because the longjmp() and setjmp() functions are not part of the C++ language, the header files included with the Microsoft C++ compiler do not allow the use of the longjmp() and signal() functions in a C++ program. These functions are needed to trap floating-point exceptions. This article explains why these functions are not defined, and how you can trap floating-point exceptions in C++.


MORE INFORMATION

Using longjmp() in C is potentially dangerous because if you dynamically allocate memory, then do a longjmp() before freeing the memory, that memory may end up never being freed.

The longjmp() and setjmp() functions are not part of the C++ language because in C++, longjmp() is potentially more dangerous. There is significantly more implicit dynamic memory allocation taking place in C++, with many new and delete operations occurring as objects are constructed and deleted. For this reason, longjmp() and setjmp() are not defined when compiling C++ programs. Both longjmp() and setjmp() are within a "#ifndef __cplusplus" section in SETJMP.H.

In C++, exceptions are normally handled by try catch blocks. You can use TRY and CATCH to catch some exceptions predefined in the Microsoft Foundation Classes (MFC), such as CFileException and CMemoryException; however, there are no exception classes for floating-point errors.

There is a technique similar to that used by the Microsoft Foundation Classes that you can use to trap floating-point exceptions using C++; that is, prototype longjmp() and setjmp() yourself. Also, to allow signal() to be called with either a handler that takes two parameters (_SIG_FPE) or just one parameter (all other signal values), signal() must be prototyped differently to accept a handler with a variable-length function list. The new prototype could be:


   void (__cdecl * __cdecl signal(int, void (__cdecl *)(int, ...)))(int); 
In this case, whenever you call signal(), you must cast its second parameter with the following cast:

   (void (__cdecl *)(int, ...)) 
Appended below is SIGCPP.H, a header file that consists of the modified and combined header files SIGNAL.H and SETJMP.H. To use it, #include <sigcpp.h>, and make sure that SIGNAL.H and SETJMP.H are not included--and remember to use the above cast in signal() calls.

NOTE: This solution is not guaranteed to work in every case. If used with care, this solution will probably work; however, Microsoft does not recommend the use of longjmp() with C++. Using longjmp() with C++ may result in objects not being properly destroyed. If the objects that aren't destroyed allocate resources such as memory or file handles, these resources will not be deallocated.

Sample Code


/***
* SIGCPP.H - Header file that allows the use of signal() for the
* handling of floating point and other exceptions in both C and C++.
* However, it is recommended that longjmp() not be used in C++ programs.
*  - Do not #include <signal.h> or <setjmp.h>.
*  - Whenever you call signal(), you need to put the following cast on
*    its second parameter, your handler:
*       (void (__cdecl *)(int, ...))
*  - Be very careful to avoid memory leakage with longjmp()'s in C++,
*    which will occur if destructors and other deletes are jumped.
****/ 

#ifndef _INC_SIGCPP

#ifdef __cplusplus
extern "C" {
#endif

#if (_MSC_VER <= 600)
#define __cdecl     _cdecl
#define __far       _far
#endif

////// Modified SIGNAL.H definitions:

#ifndef _SIG_ATOMIC_T_DEFINED
typedef int sig_atomic_t;
#define _SIG_ATOMIC_T_DEFINED
#endif

#define NSIG 23     /* Maximum signal number + 1 */ 

/* signal types */ 

#ifndef _WINDOWS
#define SIGINT  2  /* CTRL+C sequence */ 
#define SIGILL  4  /* Illegal instruction - invalid function image */ 
#endif
#define SIGFPE  8  /* Floating-point exception */ 
#ifndef _WINDOWS
#define SIGSEGV 11 /* Segment violation */ 
#define SIGTERM 15 /* Software termination signal from kill */ 
#define SIGABRT 22 /* Abnormal termination triggered by abort call */ 
#endif

/* SIGNAL ACTION CODES */ 

/* Default signal action */ 
#define SIG_DFL (void (__cdecl *)(int))0

/* Ignore */ 
#define SIG_IGN (void (__cdecl *)(int))1

/* Signal error value (returned by signal call on error) */ 
#define SIG_ERR (void (__cdecl *)(int))-1

/* FUNCTION PROTOTYPES */ 

void (__cdecl * __cdecl signal(int,
     void (__cdecl *)(int, ...)))(int);
int __cdecl raise(int);

////// Modified SETJMP.H definitions:

/* Define the buffer type for holding the state information */ 

#define _JBLEN  9  /* bp, di, si, sp, ret addr, ds */ 

#ifndef _JMP_BUF_DEFINED
typedef  int  jmp_buf[_JBLEN];
#define _JMP_BUF_DEFINED
#endif

/* Function prototypes */ 

int  __cdecl setjmp(jmp_buf);
void __cdecl longjmp(jmp_buf, int);

#ifdef __cplusplus
}
#endif  /* __cplusplus */ 

#define _INC_SIGCPP
#endif  /* _INC_SIGCPP */ 
 

Additional query words: kbinf 1.00 1.50 7.00 8.00 8.00c


Keywords          : kb16bitonly 
Version           : 
Platform          : 
Issue type        : 

Last Reviewed: July 28, 1999