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.7 <signal.h>  toptop

Signale sind nicht vorhersehbare Ereignisse, die zu einem nicht vorhersagbaren Zeitpunkt auftreten können, also asynchrone Ereignisse. Nach dem ANSI C-Standard gibt es folgende Signale, die vorkommen können:


Tabelle 22.5   Makros für Fehlersignale

Name Bedeutung
SIGABRT Dieses Signal signalisiert, dass sich das Programm abnormal beendet hat (abort()).
SIGFPE Dieses Signal wird z.B. angezeigt bei einer Division durch 0 oder einem Überlauf einer Zahl.
SIGILL Dieses Signal wird angezeigt, wenn ein illegaler Hardware-Befehl ausgeführt wird.
SIGINT Dieses Signal wird an alle Prozesse geschickt, wenn die Tastenkombination (Strg) + (C) gedrückt wurde.
SIGSEGV Wird dies angezeigt, wurde versucht, auf eine unerlaubte Speicherstelle zu schreiben oder zu lesen.
SIGTERM Beendigung eines Programms

Unter Linux gibt es deutlich mehr Signale (ca. 30). Mit dem Befehl

kill –l

wird eine Liste der Signale unter Linux/UNIX ausgegeben. Tritt ein Signal auf, haben Sie folgende Möglichkeiten, darauf zu reagieren:

gp  Eintragen einer selbst geschriebenen Funktion
gp  Ignorieren des Signals (geht aber nicht mit SIGKILL)
gp  Verwenden der voreingestellten Default-Funktion (bei den ANSI C-Signalen ist dies immer eine Beendigung des Programms)

Um auf die Signale zu reagieren, existiert ein so genanntes Signalkonzept. Dabei richtet ein Prozess einen so genannten Signalhandler ein. Dieser Signalhandler teilt – wenn das Signal auftritt – dem Systemkern mit, was er zu tun hat. Ein solcher Handler kann mit der Funktion signal() eingerichtet werden. Hier ihre Syntax:

#include <signal.h>
void(*signal(int signr, void(*sighandler)(int)))(int);

Einen solchen Prototypen zu lesen, ist fast unmöglich. Aus diesem Grund wurde die Funktion in der Headerdatei <signal.h> wie folgt vereinfacht:

typedef void (*__p_sig_fn_t)(int);
__p_sig_fn_t signal(int, __p_sig_fn_t);

Somit sieht der Prototyp folgendermaßen aus:

signalfunktion *signal(int signalnummer,
                       signalfunktion *sighandler);

Mit dem Parameter signalnummer legen Sie die Nummer des Signals fest, für die ein Signalhandler eingerichtet werden soll. Dies ist dann eines der Signale, welche Sie soeben in der Tabelle kennen gelernt haben (bzw. unter Linux diejenigen, die mit kill –l aufgelistet wurden).

Für den Parameter sighandler sind zwei Konstanten in der Headerdatei <signal.h> deklariert, SIG_DFL und SIG_IGN. Mit SIG_DFL wird die Default-Aktion ausgeführt, was meist die Beendigung des Prozesses bedeutet. Ein Beispiel:

signal(SIGINT, SIG_DFL);

Falls Sie die Tastenkombination (Strg) + (C) drücken, wird die Default-Einstellung des Signals SIGINT ausgeführt. Und die Default-Einstellung schreibt vor, dass das Programm beendet wird. Als zweite Möglichkeit können Sie Folgendes eingeben:

signal(SIGINT, SIG_IGN);

Drücken Sie jetzt die Tastenkombination (Strg) + (C), passiert gar nichts. Das Signal SIGINT wird mit der Angabe von SIG_IGN ignoriert. Als dritte Möglichkeit können Sie das Signal SIGINT abfangen und die Adresse einer eigenen Funktion übergeben, welche ausgeführt werden soll, wenn die Tastenkombination (Strg) + (C) betätigt wurde:

signal(SIGINT,funktionsaufruf);

Jetzt wird es Zeit, zu sehen, wie die Funktion signal() in der Praxis eingesetzt wird:

/* signal1.c */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigfunc(int sig) {
   int c;
   if(sig != SIGINT)
      return;
   else {
      printf("\nWollen Sie das Programm beenden (j/n) : ");
      c=getchar();
      if(c == 'j')
         exit (EXIT_FAILURE);
      else
         return;
   }
}
int main(void) {
   int i;
   signal(SIGINT, sigfunc);
   while(1) {
      printf("Mit STRG+C beenden");
      for(i = 0; i <= 48; i++)
         printf("\b");
   }
   return EXIT_SUCCESS;
}

Mit der Anweisung

signal(SIGINT, sigfunc);

wird ein Signalhandler für das Signal SIGINT eingerichtet, der beim Auftreten dieses Signals die Funktion sigfunc aufrufen soll.

Ein einfaches Beispiel bietet auch das Erstellen einer eigenen kleinen Shell. Die einzelnen Shellbefehle werden in einer Endlosschleife abgearbeitet. Mit der Tastenkombination (Strg) + (C) lösen Sie dabei einen Neustart der Shell aus. Dieser Sprung (Neustart) wird mit den Funktionen der Headerdatei <setjmp.h> realisiert. Hier das Beispiel dazu:

/* a_simple_shell.c */
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#define MAX 255
#define OK 0
jmp_buf restart;
void ctrlc(int sig) {
   signal(sig, ctrlc);
   /* Zurück zur Kommandozeile */
   longjmp(restart, 1);
   return;
}
int main(void) {
   char *command;
   /* Installiere den Signalhandler */
   signal(SIGINT, ctrlc);
   if(setjmp(restart) != 0)
      printf("\n\nShell neu gestartet ...\n\n");
   else
      printf("\n\nShell gestartet ...\n\n");
   for (;;) {   /* Hier können Sie machen, was Sie wollen */
      char puffer[MAX];
      printf("$~> ");
      fgets(puffer, MAX, stdin);
      command = strtok(puffer, "\n");
      if( strcmp(command, "test") == OK )
         printf("Ihr Befehl lautete \"test\"\n");
      else if( strcmp(command, "help") == OK )
         printf("Brauchen Sie Hilfe?\n");
      /* usw. eine Menge mehr Shellbefehle …*/
      else if( strcmp(command, "exit") == OK )
         exit (EXIT_SUCCESS);
      else {
         printf("\nUnbekannter Shellbefehl\n");
         printf("Bekannte Befehle: test, help, exit\n\n");
      }
   }
   return EXIT_SUCCESS;
}

Dies ist eine einfache Schnittstelle einer eigenen Shell. Logischerweise müssen Sie statt der Ausgabe von Texten Ihre selbst geschriebenen Funktionen implementieren.

Ein weiteres Beispiel zu signal() mit dem Signal SIGABRT.

/* sigabort.c */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigfunc(int sig) {
   if(sig == SIGABRT)
      printf("Demonstration von SIGABRT\n");
}
int main(void) {
   signal(SIGABRT, sigfunc);
   abort();
   return EXIT_SUCCESS;
}

Um zu testen, ob der Aufruf der Funktion signal() überhaupt erfolgreich war, befindet sich in der Headerdatei <signal.h> der Fehlercode SIG_ERR, der mit dem Wert –1 definiert ist. Wollen Sie also die Funktion signal() auf Fehler überprüfen, sollte dies so aussehen:

if( signal(SIGINT,sigfunc) == SIG_ERR)
   {  /* Fehler beim Aufruf von signal */

Es ist auch möglich, ein Signal an ein ausführendes Programm mit der Funktion raise() zu senden. Die Syntax der Funktion:

int raise(int signr);

Damit können Sie ein Signal mit der signr an das Programm senden. Ein kurzes Beispiel:

/* raise_signal.c */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigfunc(int sig) {
   if(sig == SIGINT)
      printf("SIGINT wurde ausgelöst\n");
}
int main(void) {
   signal(SIGINT,sigfunc);
   printf("Mit ENTER SIGINT auslösen\n");
   getchar();
   /* SIGINT auslösen */
   raise(SIGINT);
   return EXIT_SUCCESS;
}

Unter Linux/UNIX verwendet man allerdings in Praxis ein etwas anderes Signalkonzept, da die signal()-Funktion von ANSI C hier einige Schwächen besitzt. Mehr dazu können Sie wieder aus meinem Buch »Linux-UNIX-Programmierung« entnehmen, welches Sie auch auf meiner Webseite zum Online-Lesen vorfinden.

 << 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