Blog der Heimetli Software AG

setjmp und longjmp

Vermutlich kennen nicht mehr allzuviele C-Hacker die beiden Funktionen, denn man sieht sie sehr selten.

Es ist aber auch ratsam, sie nur in speziellen Fällen einzusetzen, denn Code mit vielen setjmp- und longjmp-Aufrufen wäre wohl kaum zu durchschauen.

Was sind setjmp und longjmp ?

setjmp ist vergleichbar mit einem try/catch in C++ oder Java, und longjmp ist vergleichbar mit throw. In diesem Satz steht ausdrücklich vergleichbar und nicht gleich!

setjmp speichert den aktuellen Stackframe in einem Buffer vom Typ jmp_buf. longjmp setzt den Stack zurück an diesen Punkt, und alle Aufrufe nach setjmp sind vergessen. Der Stack wird auf einen Schlag zurückgesetzt, egal wie viele Aufrufe seither passiert sind.

Die C++ Rreferenz warnt explizit davor, setjmp und longjmp in C++ Programmen zu nutzen, weil sie die Objekte auf dem Stack nicht aufräumen sondern einfach vergessen.

setjmp definiert also einen Ort an den das Programm zurückkehren kann, und longjmp veranlasst die Rückkehr. Das ist vor allem praktisch wenn in einer Funktion ein Fehler auftritt, und man rasch und ohne grosse Komplikationen wieder zum Ausgangspunkt will.

Das interessante an setjmp ist, dass die Funktion nicht nur einmal zurück kommt. Beim Aufruf wird der Stackframe gesichert und die Funktion liefert den Returnwert 0. Wenn longjmp nicht aufgerufen wird (der Normalfall), war's das auch schon.

Tritt ein Fehler im Programm auf, kommt longjmp ins Spiel, und der Stack wird zurückgesetzt, genau an die Position wo er in der Funktion setjmp gespeichert wurde. Der Code kommt also ein zweites mal aus der Funktion setjmp heraus!

Damit man diese beiden Fälle unterscheiden kann, ist der Returnwert diesmal nicht 0, sondern ein Wert der longjmp mitgegeben wird.

Beispielcode

Das folgende Programm nutzt die beiden Funktionen um die bekannte Meldung aus dem ersten Beispielprogramm im Buch von Kernighan und Ritchie auszugeben.

/*****************************************************************************/
/*                                                                           */
/*                                                         FILE: hellojump.c */
/*                                                                           */
/*   Demonstrates the use of setjmp and longjmp                              */
/*   ==========================================                              */
/*                                                                           */
/*   Compiled with gcc 4.9.2                                                 */
/*                                                                           */
/*   V1.00  05-OCT-2015   Te                                                 */
/*                                                                           */
/*****************************************************************************/

#include <stdio.h>
#include <setjmp.h>

jmp_buf env ;

static char *message = "Hello world !\n" ;

/*******************/
 void print( int i )
/*******************/

{
   putchar( message[i] ) ;
   longjmp( env, 1 ) ;
}

/**********/
 int main()
/**********/

{
   int i = 0 ;

   for( ;; )
   {
      if( setjmp(env) == 0 )
      {
         print( i ) ;
      }
      else
      {
         if( message[i++] == '\0' )
            return 0 ;
      }
   }
}

Wem dieser Code gefällt, der findet bei Grusel++ of the month eine ganze Reihe solcher Programme.