Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 22 Weitere Headerdateien und ihre Funktionen (ANSI C)
  gp 22.1 <assert.h> -– Testmöglichkeiten und Fehlersuche
  gp 22.2 <ctype.h> – Zeichenklassifizierung und Umwandlung
  gp 22.3 Mathematische Funktionen – <math.h>
  gp 22.4 <stdlib.h>
    gp 22.4.1 Programmbeendigung – exit(), _exit(), atexit() und abort()
    gp 22.4.2 Konvertieren von Strings in numerische Werte
    gp 22.4.3 Bessere Alternative – Konvertieren von Strings in numerische Werte
    gp 22.4.4 Zufallszahlen
    gp 22.4.5 Absolutwerte, Quotient und Rest von Divisionen
    gp 22.4.6 Suchen und Sortieren – qsort() und bsearch()
    gp 22.4.7 system()
  gp 22.5 <locale.h> – Länderspezifische Eigenheiten
  gp 22.6 <setjmp.h>
  gp 22.7 <signal.h>
  gp 22.8 <string.h> – Die mem…-Funktionen zur Speichermanipulation
    gp 22.8.1 memchr() – Suche nach einzelnen Zeichen
    gp 22.8.2 memcmp() – Bestimmte Anzahl von Bytes vergleichen
    gp 22.8.3 memcpy() – Bestimmte Anzahl von Bytes kopieren
    gp 22.8.4 memmove() – Bestimmte Anzahl von Bytes kopieren
    gp 22.8.5 memset() – Speicherbereich mit bestimmten Zeichen auffüllen
  gp 22.9 Erweiterter ANSI C-Standard (ANSI C99)
    gp 22.9.1 Neue elementare Datentypen
    gp 22.9.2 <stdint.h> – Ganzzahlige Typen mit vorgegebener Breite
    gp 22.9.3 Komplexe Gleitpunkttypen
    gp 22.9.4 <iso646.h> – Symbolische Konstanten für Operatoren
    gp 22.9.5 Deklaration von Bezeichnern
    gp 22.9.6 inline-Funktionen
    gp 22.9.7 Vordefinierte Makros
    gp 22.9.8 <math.h> – Neue Funktionen
    gp 22.9.9 <wchar.h> – (NA1)
    gp 22.9.10 <wctype.h> (NA1)
    gp 22.9.11 <fenv.h> – Kontrolle der Gleitpunkzahlen-Umgebung
    gp 22.9.12 <inttypes.h> – Für genauere Integer-Typen
    gp 22.9.13 <tgmath.h> – Typengenerische Mathematik-Funktionen
    gp 22.9.14 Zusammenfassung


Galileo Computing - Zum Seitenanfang

22.6 <setjmp.h>  toptop

In C sind Sprünge über Funktionsgrenzen hinweg nicht erlaubt. Das heißt genau, Funktionen werden immer an den direkten Ausrufer zurückgegeben. Wenn z.B. Funktion 1 die Funktion 2 aufruft, kehrt Funktion 2 immer zuerst zur Funktion 1 zurück; eben in der umgekehrten Reihenfolge, wie die einzelnen Funktionen auf (genauer: unter) dem Stack abgelegt wurden. Erst dann kann Funktion 1 zu ihrem Ausrufer zurückkehren. Ein Beispiel:

/* call_func.c */
#include <stdio.h>
#include <stdlib.h>
void func1(void);
void func2(void);
void func3(void);
void func4(void);
void func1(void) {
   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(void) {
   printf("Funktion 4 ist augerufen!\n");
}
int main(void) {
   func1();
   return EXIT_SUCCESS;
}

Das Programm ruft in der main()-Funktion zuerst func1() auf, func1() ruft anschließend func2() auf, func2() ruft danach func3() auf und func3() ruft am Ende func4() auf. Anschließend kehren die einzelnen Funktionen wieder in der Reihenfolge func3(), func2() und func1() zur main()-Funktion zurück. Was wäre jetzt, wenn in func2() eine Berechnung durchgeführt wird und der Wert dieser Berechnung nicht mehr dem entspricht, den der Nutzer sich versprochen hat? Trotzdem werden sinnloserweise noch func3() und func4() aufgerufen und ausgeführt. Die Frage lautet also, wie kann man z.B. von func2() zur main()-Funktion zurückspringen, Funktionen func3() und func4() auslassen und auch nicht mehr über func1() zur main()-Funktion zurückzukehren?

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 22.2   Rückkehr von Funktionen bei einem normalen Verlauf

Dafür können Sie die Funktionen der Headerdatei <setjmp.h> verwenden. Hier die Syntax:

#include <setjmp.h>
jmp_buf env;    // Primitiver Datentyp jmp_buf
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int wert);

Der Datentyp jmp_buf env ist eine Art Puffer, der den mit setjmp(env) eingefrorenen Programmzustand enthält und den Sie mit der Funktion longjmp(env,1) wiederherstellen können. jmp_buf enthält zum Beispiel die CPU-Registerinhalte (CS, DS, SS und ES), den Stackpointer (SP), den Instruktionspointer (IP) usw. – alle Informationen eben, die erforderlich sind, um den gleichen Zustand wieder herzustellen, der vor dem Aufruf von setjmp() vorlag.

Mit setjmp() werden, wie eben schon erwähnt, alle Informationen, die im Augenblick vorliegen, auf einen Stack gelegt. Der Aufruf von setjmp() lautet:

if(setjmp(env) == 0)

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

Mit der Funktion longjmp() kehren Sie dann an diese Programmstelle zurück, die Sie mit setjmp(env) auf dem Stack abgelegt haben. Dies geschieht mit folgendem Aufruf:

longjmp(env,1);

Nochmals alles zusammengefasst:

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

Als Erstes legen Sie hier mit setjmp() den Programmzustand auf den Stack. Anschließend, viele Funktionen später, wird mit longjmp() dieser Zustand wiederhergestellt und springt zurück zu setjmp(). Dieses Mal ist der Rückgabewert von setjmp() aber nicht mehr 0, und daher fährt das Programm hinter der else-Anweisung fort.

Jetzt soll alles in einem Programm verwendet werden, ohne komplizierte Berechnungen oder Ähnliches. Es wird einfach abgefragt, wie viele Funktionen ausgeführt werden sollen, und das Programm springt nach der gewünschten Anzahl der Funktionen mit einem Aufruf von longjmp() zur main()-Funktion zurück:

/* setjmp.c */
#include <stdio.h>
#include <stdlib.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(void) {
   printf("Funktion 4 ist augerufen!\n");
}
int main(void) {
   printf("Wie viele 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 EXIT_SUCCESS;
}

Die Funktionen setjmp() und longjmp() haben übrigens nichts mit der Anweisung goto gemeinsam. Es hat sich als recht nützlich erwiesen, setjmp() und longjmp() bei Fehlerbehandlungen einzusetzen.

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de