I'm a fairly experienced C programmer, but just realized something for the first time today which I find very cool (and useful): one can implement exception handling in ANSI C. I'll show in detail here how it's done.
The whole thing comes down to two standard ANSI functions:
setjmp and longjmp .
Their prototypes are:
#include <setjmp.h> int setjmp(jmp_buf jb); void longjmp(jmp_buf jb, int val);
Now here's how they work. You call setjmp at some
point in your code on the jmp_buf jb,
for instance; it returns zero. Later on, at any point, you
can call longjmp(jb, val), for some integer
val. This, in effect, returns execution back to the
setjmp function which this time returns val.
For example, consider the following code segment:
jmp_buf jb;
void f2() {
longjmp(jb, 1);
}
void f1() {
if (!setjmp(jb)) {
printf("first time\n");
f2();
} else {
printf("second time\n");
}
}
Let's trace through a call to f1. First,
setjmp is called on jb. The return
value is zero. The message "first time" is
printed on the screen and f2 is called.
The function f2 immediately calls longjmp.
This returns execution back to the line with the setjmp,
and has the same effect as that setjmp returning
with return value 1. Thus the else block is
executed and the message "second time" is
printed.
Once you have setjmp and longjmp,
implementing exceptions becomes easy. I've done it like this:
I declare two global variables:
jmp_buf __exbuf; int __exvalue;and then define macros
#define TRY __exvalue=setjmp(__exbuf); \
if (__exvalue==0) { __pushtry();
#define CATCH(x) __poptry(); } else { \
struct __ex_t *x; \
(x)=(struct __ex_t *)__exvalue; \
__poptry();
#define ENDTRY }
(here __ex_t is just some structure which has
information about the exception). The functions
__pushtry and __poptry explain
themselves. To throw an exception, just do a
longjmp to the jmp_buf on the
top of the stack.
Assuming we have functions xfopen and
xfclose which work like fopen
and fclose except they generate exceptions
on errors, we could use the above structure as follows:
FILE *inf;
TRY
inf=xfopen("test.txt", "rt");
printf("file opened successfully\n");
xfclose(inf);
CATCH(ex)
print_ex_info(ex);
ENDTRY
If you prefer, you can enclose your TRY and
CATCH block in braces; it doesn't really
matter though.