tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Exceptions in C

>> Before I start reinventing a wheel, does anyone know if there is
>> already an API for doing this sort of thing, either in libc or some
>> other library?
> The only portable way to do this is setjmp/longjmp.

True...for suitable values of "portable" (which here approximately
equals "promised by the C and POSIX specs").

Using gcc extensions allows implementing catch/throw-style control flow
without the ugly restrictions of longjmp (for example, it doesn't risk
doing unfortunate things to non-volatile auto variables).  If depending
on gcc is portable enough for you, that might be of use.

> Depending on how often you want to enter a exception handling context
> ("try {}"), it can be expensive though.

The gcc way will generally be substantially faster than longjmp; if
nothing else, it doesn't involve a trap to the kernel.  Of course, it
also has restrictions; for example, you probably do not want to use it
to throw out of a signal handler, because it won't restore the
signal-handling state the way longjmp does.

If you want to try it, it'd be something like

void (*throw_out)(int);

void try_something(void)
 __label__ catcher;

 int cause;

 void thrower(int value) { cause = value; goto catcher; }

 throw_out = &thrower;
 ...code, which calls (say) attempt()...
catcher: /* come here upon a throw */
 ...handle the throw...

/* attempt() may be in a different file from try_something, even;
   it just needs throw_out to be visible */
void attempt(void)
 if (something) (*throw_out)(somevalue);

This version passes an int from the point of throw to the point of
catch.  You can of course pass whatever you want, by making the thrower
function take other arguments.  (Pointers require care to make sure the
pointed-to object is not taken out of scope by the throw, in which case
the pointer isn't much use.  But that's no different from longjmp.)
And, of course, you must always throw _out_; if you call (*throw_out)()
after try_something() has returned, then, in the words of the gcc
documentation, all hell will break loose.

If you're tempted to use the other gcc goto extension, as in

void *throw_to;

void try_something(void)
 __label__ catcher;

 throw_to = &&catcher;

void attempt(void)
 ... if (something) goto *throw_to; ...

...don't.  This mechanism is documented as doing "totally unpredictable
things" when used to jump between functions.

/~\ The ASCII                             Mouse
\ / Ribbon Campaign
 X  Against HTML      
/ \ Email!           7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B

Home | Main Index | Thread Index | Old Index