ein Kapitel zurück                                           ein Kapitel weiter

In C sind Sprünge über Funktionsgrenzen nicht erlaubt. Das heißt Funktionen werden immer an den direkten Aufrufer zurückgegeben. Wenn z.B. Funktion1 die Funktion2 aufruft, kehrt die Funktion2 immer zuerst zur Funktion1 zurück. Erst dann kann Funktion1 zu seinem Aufrufer zurückkehren. Beispiel....

/*Download:jmp1.c*/
#include <stdio.h> void func1(void); void func2(void); void func3(void); void func4(void); void func1() { printf("Funktion 1 ist aufgerufen!\n"); func2(); } void func2(void) { printf("Funktion 2 ist aufgerufen!\n"); func3(); } void func3(void) { printf("Funktion 3 ist aufgerufen!\n"); func4(); } void func4() { printf("Funktion 4 ist augerufen!\n"); } int main() { func1(); return 0; }

Das Programm ruft von der main-Funktion zuerst func1, func1 ruft dann func2 auf, func2 ruft func3 und func3 ruft func4 auf. Anschließend kehren die Funktionen wieder in der Reihenfolge ->func3,func2,func1 zur main-Funktion zurück. Was aber wenn jetzt in func2 eine Berechnung durchgeführt wird und der Wert dieser Berechnung nicht mehr dem entspricht was sich der Bediener versprochen hat und trotzdem sinnloser weise wird noch func3 und func4 aufgerufen und ausgeführt. Die Frage lautet also wie können wir z.B. von func2 zur main-Funktion zurückspringen und Funktionen func3 und func4 ignorieren und auch nicht mehr zur func1 zurückkehren um dann erst wieder zur main-Funktion zurückzukehren?

Dazu haben wir in der Headerdatei <setjmp.h> folgende Funktionen....

#include <setjmp.h>

jmp_buf env;    //Datentyp jmp_buf

int setjmp(jmp_buf env)

void longjmp(jmp_buf env, int wert);  

Kommen wir zuerst zum Datentyp jmp_buf env . Dieser Datentyp ist der Puffer der den mit setjmp(env) eingefrorenen Programmzustand enthält der mit longjmp(env,1) wiederhergestellt werden soll. In jmp_buf sind enthalten z.B. die Registerinhalte(CS,DS,SS,ES), Stackpointer (SP), Instructionspointer (IP)...eben alle Informationen die nötig sind um den GLEICHEN Zustand wiederherzustellen der vor dem Aufruf von setjmp vorlag.

Mit setjmp legen sie eben schon erwähnt alle Informationen die im Augenblick vorliegen auf einem Stack. Der Aufruf von setjmp lautet z.B....

if(setjmp(env) == 0)  

Beim 1. Aufruf von setjmp liefert die Funktion auch den Wert 0 zurück. Beim 2. Aufruf durch longjmp(env) liefert die Funktion auf jeden Fall einen Wert ungleich 0 zurück.

Mit longjmp kehren wir dann an die Programmstelle zurück die wir mit setjmp(env) auf dem Stack abgelegt haben. Dies geschieht mit...

longjmp(env,1);  

Fassen wir das ganze nochmals zusammen....

......
jmp_buf programmzustand;
......
if(setjmp(programmzustand)==0)
    printf("Programmzustand auf dem Stack gelegt\n");
else
    printf("Rücksprung mit longjmp erfolgt\n");
.........
........
viele,viele Funktionen
longjmp(programmzustand,1);  

Als erstes legen wir hier mit setjmp den Programmzustand auf dem Stack. Was mit printf auch ausgegeben wird. Anschließend nach vielen Funktionen rufen wir mit longjmp diesen Zustand wieder auf und springen wieder hoch zu setjmp. Dieses mal ist setjmp aber nicht mehr ==0 und daher fährt das Programm hinter der else - Anweisung fort und gibt die 2. printf - Anweisung aus.

Jetzt wollen wir das ganze in unser Programm einbauen. Aber ohne komplizierte Berechnungen oder ähnliches. Wir begnügen uns lediglich mit der Abfrage wie viele Funktionen ausgeführt werden sollen und führen eben nach der gewünschten Anzahl der Funktionen einen longjmp zur main-Funktion aus....

/*Download:jmp2.c*/
#include <stdio.h> #include <setjmp.h> void func1(int); void func2(int); void func3(int); void func4(void); jmp_buf env; static int zahl; void func1(int zahl) { printf("Funktion 1 ist aufgerufen!\n"); if(zahl==1) longjmp(env,1); func2(zahl); } void func2(int zahl) { printf("Funktion 2 ist aufgerufen!\n"); if(zahl==2) longjmp(env,2); func3(zahl); } void func3(int zahl) { printf("Funktion 3 ist aufgerufen!\n"); if(zahl==3) longjmp(env,3); func4(); } void func4() { printf("Funktion 4 ist augerufen!\n"); } int main() { printf("Wieviele Funktionen sollen ausgeführt werden : "); scanf("%d",&zahl); if(setjmp(env) == 0) func1(zahl); else printf("Rücksprung durch longjmp von Funktion %d!\n",zahl); return 0; }

Sie sehen wie einfach es ist von jeder beliebigen Funktion zur main - Funktion zurückzuspringen. setjmp und longjmp sind den Assemblerbefehlen PUSH und POP nicht unähnlich. Für goto - Hasser muss ich auch noch dazu sagen das setjmp und longjmp nicht mit goto gemeinsam haben. Des weiteren hat es sich auch als nützlich erwiesen setjmp und longjmp bei Fehlerbehandlungen einzusetzen.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf