[comp.lang.c] Help on use of setjmp

agostino@concour.cs.concordia.ca (Agostino Deligia) (04/26/91)

Hello,

	Could anyone out there e-mail me an example on how to use setjmp() and
longjmp() to return from a low-level function to an upper-level function?

For example:

void Parse(void) {
  Init();
  DoIt();

  fini:  /* this is where to jump to before quitting Parse() */
  CleanUp();
}

...

void P_E(void) {
  ...
  P_F();
  ...
}

void P_F(void) {
  ...

  if (error)
    /* jump to 'fini' in Parse() */

  ...
}

I read the man pages for setjmp()/longjmp(), but the code fragment they give
doesn't help much.  Also, the only book on C that I have doesn't cover
setjmp()/longjmp().

Any help would be greatly appreciated.  Thank-you.

Agostino Deligia

--
-------------------------------------------------------------------------------
       OO OO     Agostino Deligia
      O O   O    Systems Architecture
     O  O   O    Concordia University, Montreal (Canada)

john@newave.UUCP (John A. Weeks III) (04/27/91)

In article <215@daily-planet.concordia.ca> agostino@concour.cs.concordia.ca (Agostino Deligia) writes:

> Could anyone out there e-mail me an example on how to use setjmp() and
> longjmp() to return from a low-level function to an upper-level function?

> I read the man pages for setjmp()/longjmp(), but the code fragment they
> give doesn't help much.  Also, the only book on C that I have doesn't cover
> setjmp()/longjmp().

I'll say--I had to see them work before I caught on.  An example can be
found in the book "UNIX Programming Environment" by Kernighan and Pike.
This book, often refered to as K&P, is a must have for anyone with interest
in UNIX and C.  Another good book is Using C On The UNIX System by the
Nutshell people (O'Reilly & Associates).

Think of the setjmp() procedure this way.  When your program executes it,
it sort of appears to do nothing.  But when you call longjmp() later on,
your program appears to start executing as if the setjmp() procedure was
just called.  It acts like a goto.

Setjmp() does actually do something when it is called.  It saves some
facts about your program.  This information is needed so the program can
pick up running at the setjmp() when your longjmp() is called.  It needs
a program storage area called a jmp_buf.  It stores things like register
values and the stack pointer.

The real trick is how does your program know if you are returning from
setjmp() because you called setjmp(), or because you called longjmp()?
The return value of setjmp() lets you know.  If you call setjmp(), it
returns 0.  If longjmp() is called, an integer passed as the second
parameter to longjmp() is returned by setjmp().

Why would you want to use setjmp()?  I think that it is pretty ugly, just
another type of goto, but I like to use it in my error traping code.
Often you want to exit() when you get an error, but sometimes you need
to do some type of clean-up work.  You can longjmp() back somewhere and
do whatever you need to do in a central location.

Here is an example:

jmp_buf retbuf;

main()
{
/* do some stuff */

  if ( setjmp( retbuf ) == 0 )
  {
    someproc()
  }
  else
    printf( "exit on some error\n" );

  exit( 0 );
}

void someproc( void )
{
/* do some stuff */

  if ( some_type_of_error() )
    longjmp( retbuf, 1 );

/* do some more stuff */
}

When main() executes, setjmp is called the first time.  It returns zero,
so the someproc() routine is called.  If someproc() does not call longjmp,
it will return and the exit is executed.  If someproc() calls the longjmp,
setjmp will return nonzero, and the program will pick up executing the
printf, then exit.  Pure black magic!

-john-

-- 
=============================================================================
John A. Weeks III               (612) 942-6969             john@newave.mn.org
NeWave Communications                       ...uunet!tcnet!wd0gol!newave!john