![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() ![]()
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....
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?
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.
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.
Fassen wir das ganze nochmals zusammen....
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.
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. ![]() ![]() ![]() |