How to Trap Floating-Point Exceptions Using C++Last reviewed: July 22, 1997Article ID: Q106261 |
7.00 | 1.00 1.50
MS-DOS | WINDOWS
WINDOWS
kbprg kbcode
The information in this article applies to:
SUMMARYIn 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 INFORMATIONUsing 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 notincluded--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 reference words: kbinf 1.00 1.50 7.00 8.00 8.00c
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |