10. Präprozessor-Befehle
  Präprozessor-Befehle (auch Compilerdirektiven genannt) sind Anweisungen
  an den Präprozessor des Compilers. Der Präprozessor ist dem Compiler vorgeschaltet,
  d.h. bei jeder Compilierung wird erst der Präprozessor gestartet, der an ihn gerichtete
  Befehle im Quellcode sucht und verarbeitet. Damit steuert der Präprozessor den
  Compilierungsvorgang.
  Präprozessor-Befehle beginnen stets mit # am Zeilenanfang. Im
  Gegensatz zu Anweisungen in C/C++ enden sie aber nicht mit einem Semikolon! In der
  folgenden Tabelle sind alle Präprozessor-Befehle aufgelistet:
  
| Präprozessor-Befehl | Bedeutung | 
| #include | Fügt Text aus einer anderen Quelltextdatei ein. | 
| #define | Definiert ein Makro. | 
| #undef | Entfernt ein Makro. | 
| #if | Bedingte Compilierung in Abhängigkeit der nachstehenden Bedingung. | 
| #ifdef | Bedingte Compilierung in Abhängigkeit, ob ein Makroname definiert ist. | 
| #ifndef | Bedingte Compilierung in Abhängigkeit, ob ein Makroname nicht definiert ist. | 
| #else | Alternative Compilierung, wenn die Bedingung des vorstehenden #if, #elif, #ifdef oder #ifndef nicht erfüllt ist. | 
| #elif 2 | Alternative Compilierung in Abhängigkeit der nachstehenden Bedingung, wenn die Bedingung des vorstehenden #if, #elif, #ifdef oder #ifndef nicht erfüllt ist (also eine Art Kombination aus #else und #if). | 
| #endif | Beendet den Block mit der bedingten Compilierung. | 
| #line | Setzt die Zeilennummer für Compiler-Meldungen. | 
| defined 1 | Liefert eine 1, wenn der nachstehende Makroname definiert ist, sonst eine 0. Kann nur zusammen mit #if und #elif verwendet werden. | 
| #-Operator 1 | Ersetzt innerhalb eines Makros einen Makroparameter durch eine konstante Zeichenkette, die den Wert des Parameters enthält. | 
| ##-Operator 1 | Erzeugt ein einzelnes Token aus zwei hintereinander stehenden Tokens. | 
| #pragma 1 | Gibt Compiler- und System-abhängige Infomationen an den Compiler. | 
| #error 1 | Erzeugt einen Fehler während der Compilierung mit der angegebenen Fehlermeldung. | 
  1 Neu in C99.
  2 Gehört nicht zum Standard-C, obwohl es von vielen Compilern unterstützt wird.
  Der Präprozessor entfernt üblicherweise alle Zeilen mit Präprozessor-Befehlen aus
  dem Quelltext und führt die entsprechenden Befehle aus. Der daraus entstehende Quelltext
  muss ein gültiges C-Programm ergeben.
  Eine Zeile, in der (außer weißen Leerzeichen) nur ein # steht,
  wird wie eine Leerzeile behandelt. Ältere C-Compiler können hier Fehlermeldungen
  liefern.
  Im Standard-C werden Leerzeichen, die vor dem # sowie zwischen
  # und dem Präprozessor-Befehl stehen, ignoriert. Ältere C-Compiler
  ignorieren diese Leerzeichen unter Umständen nicht. Daher sollte an diesen Stellen auf
  Leerzeichen verzichtet werden.
  Alle Präprozessor-Zeilen werden vor der Textersetzung der Makros erkannt. Daher kann ein
  Makro nicht einen anderen Präprozessor-Befehl erzeugen. Das folgende Beispiel erzeugt eine
  Fehlermeldung beim Compilieren.
  Beispiel:
  
  #define GETMATH #include <math.h>
  GETMATH
  
  Der Präprozessor ersetzt (erst nachdem er alle Präprozessor-Befehle erkannt hat) das
  GETMATH durch
  #include <math.h>.
  Diese Zeile bleibt dann für die Compilierung so stehen und erzeugt während der
  Compilierung einen Fehler.
  
10.1. #include
  Bereits bekannt ist die #include-Anweisung. Mit ihr wird an der
  aktuellen Stelle eine externe Datei eingelesen und in den Quellcode eingefügt. Im
  allgemeinen werden mit diesem Befehl die Header-Dateien (Dateiendung
  *.h) eingefügt, aber auch andere Quellcodedateien (Dateiendung
  *.c oder *.cpp) sind möglich. Die
  gewünschte Datei wird in spitze Klammern (<...>) gesetzt.
  Die angegebene Datei wird im Standardverzeichnis der Header-Dateien gesucht. Dieses
  Verzeichnis wird häufig auch Includeverzeichnis genannt. Um auch
  eigene Header-Dateien einlesen zu können, die meistens bei den Quellcodedateien
  gespeichert werden, wird der Dateiname in Anführungszeichen ("...")
  anstatt in spitzen Klammern gesetzt. Dabei kann auch das Laufwerk und das Verzeichnis
  angegeben werden, wenn es nicht bei den Quellcodedateien, sondern gesondert gespeichert
  wird.
  Beispiele:
  
  #include <stdio.h>   /* Includeverzeichnis     */
  #include "projekt.h" /* akt. Verzeichnis       */
  #define Makroname "my_header.h"
  #include Makroname   /* laedt Datei, die durch
                          den Makronamen
                          angegeben ist, aus dem
                          aktuellen Verzeichnis  */
  
  Bei Pfadangaben sollte aus Kompatibilitätsgründen ein Schrägstrich
  (/) anstelle des sonst üblichen Backslashs (\)
  verwendet werden. Natürlich kann auch ein Backslash verwendet werden, dann ist aber
  das Programm nicht mehr unter UNIX compilierfähig! Ferner müssen bei der
  Verwendung von Backslashs immer zwei hintereinander geschrieben werden, da der Backslash ein
  Steuerzeichen (wie z.B. \n) einleitet.
  Beispiele:
  
  #include "C:\\Verz\\header.h"           /* läuft nicht unter UNIX! */
  #include "U:/projekt/include/projekt.h"
  
  
10.2. #define, #ifdef und #ifndef
  Für die Fehlersuche werden meist Zeilen in den Quellcode eingefügt, die z.B. den
  Inhalt von Variablen anzeigen. Ist die Fehlersuche abgeschlossen, müssen alle diese
  Zeilen wieder gelöscht werden (und bei neuen Fehlern wieder geschrieben werden usw.).
  Um dieses zu vermeiden, kann für den Präprozessor ein Label definiert werden.
  Dazu wird der Befehl #define Label verwendet. Dieses Label kann
  der Präprozessor abfragen, ob es definiert ist oder nicht. Je nachdem kann der
  Präprozessor für das Compilieren Quellcodebereiche einblenden oder nicht. Diese
  Abfrage wird mit dem Befehl #ifdef Label (Abkürzung
  für #if defined) durchgeführt. Ist das Label definiert,
  werden alle folgenden Anweisungen bis zum #else oder
  #endif mit compiliert, ansonsten nicht. Um nun die Fehlersuche
  abzuschließen, braucht nur die Definition des Labels gelöscht oder auskommentiert
  zu werden. Wird es nur auskommentiert, kann es jederzeit mit minimalem Aufwand wieder
  aktiviert werden.
  Genauso wie in C/C++ kann auch ein else-Zweig eingerichtet werden. Dazu
  wird der Befehl #else benutzt.
  Beispiel:
   kap10_01.c
  kap10_01.c
  
  01 #include <stdio.h>
  02 
  03 #define TEST
  04 
  05 int main()
  06 {
  07    int a = 3, b = 5, c;
  08 
  09    c = a * b;
  10    #ifdef TEST
  11       printf("Variableninhalte:\n");
  12       printf("a = %i\nb = %i\nc = %i\n", a, b, c);
  13    #else
  14       printf("Ergebnis von %i mal %i ist %i\n", a, b, c);
  15    #endif
  16 
  17    return 0;
  18 }
  
  In diesem Beispiel wird am Anfang des Programms das Label TEST (der
  Name des Labels ist beliebig, unterliegt aber den Regeln eines Bezeichners; wird
  standardmäßig komplett in Großbuchstaben geschrieben) definiert.
  Im Verlauf des Programms wird dieses Label abgefragt, um den Inhalt der Variablen anzeigen
  zu lassen. Ist dagegen das Label nicht definiert, wird das Ergebnis der Berechnung angezeigt.
  Entsprechend umgekehrt wird mit dem Befehl #ifndef Label
  (Abkürzung für #if not defined) geprüft, ob das Label
  (noch) nicht definiert ist.
  Ein anderer Anwendungsbereich dieser Präprozessor-Befehle ist der
  Includewächter im Bereich der Header-Dateien. Wird in einem
  großen Projekt dieselbe Header-Datei mehrfach eingelesen, werden die darin
  enthaltenen Deklarationen bzw. Definitionen mehrfach ausgeführt. Dies führt zu
  Fehlern bei der Compilierung. Um dies zu verhindern, wird in der Header-Datei zuerst
  abgefragt, ob ein bestimmtes Label bereits definiert ist. Ist dies nicht der Fall
  (nämlich beim ersten Durchlauf), wird dieses Label definiert. Dann folgen alle
  Deklarationen und Definitionen der Header-Datei und am Ende das #endif.
  Wird diese Header-Datei im gleichen Compiliervorgang ein weiteres Mal eingelesen, ist das
  Label bereits definiert und der Rest der Header-Datei wird nicht wiederholt compiliert.
  Das nächste Beispiel zeigt den typischen Aufbau von Header-Dateien. Der Name des
  Labels, das definiert wird, ist meistens der Dateiname der Header-Datei, wobei der Punkt
  durch einen Unterstrich ersetzt wird. Dadurch können in mehreren Header-Dateien keine
  Labels mit dem gleichen Namen existieren. Da mit dem #define-Befehl
  auch Textersetzung gemacht wird (siehe nächster Abschnitt), würde im folgenden
  Beispiel jedes Vorkommen des Labels - z.B. als Variable - durch "nichts" ersetzt werden. Um
  dies zu verhindern, wird der Name des Labels gleichzeitig durch sich selbst ersetzt.
  Beispiel:
  
  /* Header-Datei PROJEKT.H */
  #ifndef PROJEKT_H
     #define PROJEKT_H PROJEKT_H
     /* Deklarationen und Definitionen */
  #endif /* PROJEKT_H */
  
10.3. Makros mit #define
  Ein weiterer Einsatzbereich des Befehls #define ist die Textersetzung
  im Quellcode, wobei auch Parameter erlaubt sind. Diese Textersetzungen werden auch
  Makros genannt. Der Präprozessor ersetzt vor dem Compilierungsvorgang im
  Quellcode alle Texte, die mit dem angegebenen Text identisch sind, durch den angegebenen
  Ersatztext. Im folgenden Beispiel wird angegeben, dass im Quellcode alle Vorkommen von PI
  durch die Zahl 3.14159265 ersetzen sollen. Es hat sich eingebürgert, diese Makronamen
  komplett in Großbuchstaben zu schreiben.
  Beispiel:
   kap10_02.c
  kap10_02.c
  
  01 #include <stdio.h>
  02 
  03 #define PI 3.14159265
  04 
  05 int main()
  06 {
  07    printf("PI = %f\n", PI);
  08 
  09    return 0;
  10 }
  
  Nach der Definition kann PI wie eine konstante Variable verwendet
  werden. Der Compiler bekommt diese aber gar nicht zu sehen, da vor dem Compilierungsvorgang
  ja alle Stellen, an denen PI steht, durch die angegebene Zahl ersetzt.
  Daher kann übrigens auch kein Zeiger auf PI gerichtet
  werden.
  Wie oben erwähnt, können auch Makros mit Parametern eingerichtet werden.
  Beispiel:
  #define QUADRAT(x) x * x
  Steht nun im Quelltext die Zeile
  z = QUADRAT(5);
  wird diese durch den Präprozessor umgeschrieben in
  z = 5 * 5;
  Diese Makros können das Leben eines Programmierers manchmal sehr vereinfachen, aber
  sie können auch gefährlich sein. Wie gefährlich das angegebene Makro sein
  kann, ist sehr schnell gezeigt; es braucht nur eine Summe als Parameter übergeben
  werden. Dann wird aus der Zeile
  z = QUADRAT(3 + 6);
  durch den Präprozessor folgende Zeile gemacht.
  z = 3 + 6 * 3 + 6;
  Das Ergebnis ist 27 statt 81! Was fehlt, sind Klammern. Aber auch wenn Klammern bei der
  Definition des Makros gesetzt werden, kann es zu Problemen kommen.
  #define QUADRAT(x) ((x) * (x))
  Vorsichtshalber sind nicht nur um die beiden x Klammern, sondern auch um den gesamten
  Ausdruck gesetzt worden. In der folgenden Zeile wird der Parameter vor der Übergabe um
  1 erhöht.
  z = QUADRAT(++x);
  Falsch, denn nachdem der Präprozessor die Textersetzung durchgeführt hat, steht
  folgende Zeile da.
  z = ((++x) * (++x));
  Hier wird deutlich, dass der Parameter vor der Multiplikation zweimal um 1 erhöht
  wird.
  Ferner wird mit Makros die Typkontrolle umgangen. Werden nun Parameter mit falschen
  Datentypen übergeben, wird die Fehlersuche stark erschwert.
  Aus   z = QUADRAT("Test");   wird   z = (("Test") * ("Test"));  .
  
  Fazit:
  Die Textersetzung mit dem #define-Befehl sollte im allgemeinen
  nicht verwendet werden, wenn es Alternativen gibt. Und die gibt es
  fast immer!
  
10.4. Variable Argumentenliste in Markodefinitionen
  Mit dem C99-Standard können Funktions-ähnliche Makros mit variabler
  Parameteranzahl erzeugt werden. Dazu muss als letzter bzw. als einziger Parameter
  eine Ellipse (...) angegeben werden. Diese Parameter können dann
  im Makro mit dem Bezeichner __VA_ARGS__ (Kurzfassung von variable
  arguments) verwendet werden.
  Im folgenden Beispiel wird der Inhalt der Variablen x im Debug-Modus
  auf dem Bildschirm angezeigt, ansonsten auf dem Fehlerkanal stderr
  ausgegeben.
  Beispiel:
   kap10_03.c
  kap10_03.c
  
  01 #include <stdio.h>
  02 
  03 /* in folgender Zeile "//" entfernen für Debug-Modus */
  04 // #define DEBUG
  05 
  06 #ifdef DEBUG
  07    #define PRINTF(...) printf(__VA_ARGS__)
  08 #else
  09    #define PRINTF(...) fprintf(stderr, __VA_ARGS__)
  10 #endif
  11 
  12 int main()
  13 {
  14    int x = 0;
  15 
  16    PRINTF("Variable x = %d\n", x);
  17 
  18    return 0;
  19 }
  
  Im folgenden Beispiel wird ein Makro mit variabler Parameteranzahl definiert, das die
  Parameter mit Hilfe des #-Operators (siehe unten im Abschnitt
  #-Operator) in eine Zeichenkette umwandelt. Es werden also
  die Namen der Parameter und nicht deren Inhalte ausgegeben.
  Beispiel:
   kap10_04.c
  kap10_04.c
  
  01 #include <stdio.h>
  02 
  03 #define MAKE_STRING(...) #__VA_ARGS__
  04 
  05 int main()
  06 {
  07    int a = 1, b = 2, c = 3, d = 4;
  08 
  09    printf("Die Variablen %s haben ", MAKE_STRING(a, b, c, d));
  10    printf("die Werte %i, %i, %i und %i.\n", a, b, c, d);
  11 
  12    return 0;
  13 }
  
10.5. Vordefinierte Makros
  Im Standard-C müssen bereits einige Makros im Präprozessor vordefiniert sein. Die
  Namen der vordefinierten Makros beginnen und enden jeweils mit zwei Unterstrichen. Die
  wichtigsten vordefinierten Makros sind in der folgenden Tabelle aufgelistet.
  
| Vordefiniertes Makro | Bedeutung | 
| __LINE__ | Zeilennummer innerhalb der aktuellen Quellcodedatei | 
| __FILE__ | Name der aktuellen Quellcodedatei | 
| __DATE__ | Datum, wann das Programm compiliert wurde (als Zeichenkette) | 
| __TIME__ | Uhrzeit, wann das Programm compiliert wurde (als Zeichenkette) | 
| __STDC__ | Liefert eine 1, wenn sich der Compiler nach dem Standard-C richtet. | 
| __STDC_VERSION__ | Vor dem C95-Standard war dieses Makro nicht definiert; ab dem C95-Standard liefert dieses Makro das Veröffentlichungsdatum in Form von yyyymm als long-Zahl: | 
  Beispiel:
   kap10_05.c
  kap10_05.c
  
  01 #include <stdio.h>
  02 
  03 int main()
  04 {
  05    printf("Programm wurde compiliert am ");
  06    printf("%s um %s.\n", __DATE__, __TIME__);
  07 
  08    printf("Diese Programmzeile steht in Zeile ");
  09    printf("%d in der Datei %s.\n", __LINE__, __FILE__);
  10 
  11    #ifdef __STDC__
  12    printf("Standard-C-Compiler!\n");
  13    #else
  14    printf("Kein Standard-C-Compiler!\n");
  15    #endif
  16 
  17    #if __STDC_VERSION__ > 201700L
  18    printf("Standard-C17 oder neuer\n");
  19    #elif __STDC_VERSION__ > 201100L
  20    printf("Standard-C11\n");
  21    #elif __STDC_VERSION__ > 199900L
  22    printf("Standard-C99\n");
  23    #elif __STDC_VERSION__ > 199400L
  24    printf("Standard-C95\n");
  25    #else
  26    printf("Standard-C89 oder aelter\n");
  27    #endif
  28 
  29    return 0;
  30 }
  
  Dieses Beispielprogramm gibt folgendes aus (wenn es in der Quellcodedatei
  kap10_05.c gespeichert ist und am 04.08.2022 um 15:47:45 Uhr mit einem
  Standard-C11-Compiler compiliert wurde):
  
  Programm wurde compiliert am Aug  4 2022 um 15:47:45.
  Diese Programmzeile steht in Zeile 9 in der Datei kap10_05.c.
  Standard-C-Compiler
  Standard-C11
  Auch werden für Compiler und Betriebssystem je eine Konstante vordefiniert. Die Konstanten der
  gängigen Compiler und Betriebssystem werden in den folgenden beiden Tabellen aufgelistet
  (die Liste ist schon etwas älter ...):
  
| Vordefiniertes Makro | Compiler | 
| _MSC_VER | Microsoft C ab Version 6.0 | 
| _QC | Microsoft Quick C ab Version 2.51 | 
| __TURBOC__ | Borland Turbo C, Turbo C++ und BC++ | 
| __BORLANDC__ | Borland C++ | 
| __ZTC__ | Zortech C und C++ | 
| __SC__ | Symantec C++ | 
| __WATCOMC__ | WATCOM C | 
| __GNUC__ | GNU C | 
| __EMX__ | Emx GNU C | 
| Vordefiniertes Makro | Betriebssystem | 
| __unix__ | UNIX-System | 
| __unix | UNIX-System | 
| __MS_DOS__ | MS-DOS | 
| __WIN32__ | MS Windows ab 95 | 
| __OS2__ | OS2 | 
| _Windows | Zielsystem MS Windows | 
| __NT__ | MS Windows NT | 
| __linux__ | Linux-System | 
| __FreeBSD__ | FreeBSD | 
| __OpenBSD__ | OpenBSD | 
| _SGI_SOURCE | SGI-IRIX mit Extension *.sgi | 
| _MIPS_ISA | SGI-IRIX | 
| __hpux | HP-UX | 
  Vordefinierte Makros können mit #undef nicht entfernt werden.
  
10.6. #undef
  Der Präprozessor-Befehl #undef kann dazu genutzt werden, um ein
  Label bzw. ein Makro wieder zu entfernen. Dazu muss hinter dem Befehl der Name des Labels bzw.
  des Makros gesetzt werden. Die Syntax lautet also wie folgt:
  #undef Name
  Es wird kein Fehler verursacht, wenn dieser Befehl auf einen Namen angewendet wird, der gar
  nicht oder nicht mehr definiert ist.
  Ist ein Label bzw. ein Makro erst einmal entfernt, kann anschließend ein neues Label
  bzw. ein neues Makro mit diesem Namen definiert werden.
  
10.7. #if
  Ähnlich wie bei den Befehlen #ifdef und #ifndef
  kann mit dem Befehl #if eine bedingte Compilierung erreicht werden. Mit
  dem Befehl #if werden aber nicht Labels abgefragt, sondern es können
  beliebige Bedingungen verwendet werden. Die Bedingung muss einen konstanten arithmetischen
  Wert ergeben, der als Wahrheitswert interpretiert werden kann. Dieser Wert muss bereits beim
  Compilieren feststehen.
  Der Bereich der bedingten Compilierung muss mit dem Befehl #endif
  (in einer eigenen Zeile) abgeschlossen werden. Es ist auch möglich, mit
  #else einen "Sonst"-Zweig in die bedingte Compilierung mit
  einzubringen.
  
10.8. #line
  Mit dem Präprozessor-Befehl #line können Zeilennummer und
  Dateiname für die vordefinierten Makros __LINE__ und
  __FILE__ verändert werden. Dies kann bei der Fehlersuche sinnvoll
  sein, wenn die Quellcodedatei vor dem Compilieren von einem Tool bearbeitet wird, bei dem
  Zeilen eingefügt oder mehrere Quellcodedateien zu einer zusammen gefügt werden.
  Dabei gibt es zwei Formen der Anwendung: In der ersten Form werden hinter dem Befehl die
  Zeilennummer und der Dateiname angegeben; der Dateiname muss in Anführungszeichen
  gesetzt werden. Diese Angaben gelten für die Quellcodezeile, die diesem Befehl
  folgt.
  #line n "Dateiname"
  In der zweiten Form wird der Dateiname weggelassen; dieser entspricht dann dem tatsächlichen
  Dateinamen bzw. dem angegebenen Dateinamen des vorherigen
  #line-Befehls.
  #line n
  Ältere Compiler erlauben auch eine verkürzte Schreibweise, die aber
  vom Standard-C nicht akzeptiert wird. Dabei wird das Wort
  line weggelassen:
  # n "Dateiname"
  Beispiel:
   kap10_06.c
  kap10_06.c
  
  01 #include <stdio.h>
  02 
  03 int main()
  04 {
  05    #line 12345 "Neuer_Dateiname.c"
  06    printf("Diese Programmzeile steht in Zeile ");
  07    printf("%d in der Datei %s.\n", __LINE__, __FILE__);
  08 
  09    return 0;
  10 }
  
  Dieses Beispielprogramm gibt folgendes aus (egal in welcher Quellcodedatei es gespeichert
  ist):
  Diese Programmzeile steht in Zeile 12346 in der Datei
  Neuer_Dateiname.c.
  
10.9. #-Operator
 Der #-Operator ist ein unärer Präprozessor-Operator und wird
 in Makros verwendet. Während das Makro umgesetzt wird, wird der
 #-Operator mit dem dahinter stehenden Makro-Parameter ersetzt durch den
 aktuellen Wert des Makro-Parameters eingeschlossen in Anführungszeichen. Dadurch wird
 der Wert des Makro-Parameters, der hinter dem Operator steht, in eine Zeichenkette umgewandelt,
 egal um was für einen Datentypen es sich handelt. Während die Zeichenkette erzeugt
 wird, werden mehrere hintereinander stehende Weiße Leerzeichen ersetzt durch ein
 Leerzeichen. Anführungszeichen und Backslashs, die im Makro-Parameter enthalten sind,
 bekommen noch ein zusätzliches Backslash davor gesetzt, damit die ursprüngliche
 Bedeutung erhalten bleibt.
 Beispiel:
 
 #define Makro(a) printf(#a)
 Beim Durchlauf des Präprozessors werden die Makroaufrufe
 
 Makro(7);
 Makro("\n");
 werden ersetzt durch
 
 printf("7");
 printf("\"\\n\"");
 Achtung:
 Eine Reihe von älteren C-Compilern fügen vor Anführungszeichen und Backslashs
 keinen weiteren Backslash ein. Dies ist aber im Standard-C nicht zulässig.
  
10.10. ##-Operator
  Mit dem ##-Operator lassen sich Tokens in einer Makrodefinition
  zusammenfügen. D.h. das Token vor und das Token nach dem Operator werden zu einem Token
  zusammengesetzt. Dabei wird für den zweiten Token der aktuelle Wert eingefügt,
  sofern dieser ein Makro-Parameter ist.
  Im folgenden Beispiel setzt der Präprozessor die Makros Makro(1) und
  Makro(2) korrekt in die Variablen temp1 und
  temp2 um. Da der Präprozessor die Makros vor dem Compilieren auflöst,
  wird in der Schleife das Makro Makro(i) zur Variable tempi
  umgesetzt.
  Beispiel:
   kap10_07.c
  kap10_07.c
  
  01 #include <stdio.h>
  02 
  03 #define MAKRO(i) temp ## i
  04 
  05 int main()
  06 {
  07    int temp1, temp2, tempi, i;
  08 
  09    MAKRO(1) = 5;             /* setzt die Variable temp1 auf 5    */
  10    MAKRO(2) = 7;             /* setzt die Variable temp2 auf 7    */
  11 
  12    for (i = 1; i <= 2; i++)
  13       MAKRO(i) = 0;           /* setzt 2x die Variable tempi auf 0 */
  14 
  15    printf("%i\n", MAKRO(1)); /* gibt temp1 (also 5) aus           */
  16    printf("%i\n", MAKRO(2)); /* gibt temp2 (also 7) aus           */
  17 
  18    return 0;
  19 }
  
10.11. #pragma
  Mit Hilfe des Präprozessor-Befehls #pragma können Informationen
  oder Einstellungen an den Compiler übermittelt werden. Diese Informationen und
  Einstellungen sind abhängig vom Compiler. Jeder Compiler sollte
  #pragma-Befehle ignorieren, wenn die Informationen und Einstellungen nicht
  zum Compiler passen. Dieser Befehl wurde mit dem Standard-C eingeführt.
  Beispiel:
  
  #pragma FENV_ACCESS ON
  Dieser Befehl weist den Compiler an, beim Compilieren Überwachungen und Exceptions rund
  um die Fließkomma-Arithmetik mit einzubauen.
  Mit C99 wurden dann noch die Standard-Pragmas eingeführt. Während im obigen Beispiel
  das Pragma Compiler-abhängig ist, wird im nächsten Beispiel das C99-Standard-Pragma
  (gleichen Namens) angewendet.
  Beispiel:
  
  #pragma STDC FENV_ACCESS ON
  Es gibt im C99 nur die drei folgenden Standard-Pragmas. Diese können auf
  ON, OFF oder auf DEFAULT
  (Vorgabewert des Compilers) gesetzt werden.
  
  #pragma STDC FP_CONTRACT ON
  #pragma STDC FENV_ACCESS ON
  #pragma STDC CS_LIMITED_RANGE ON
  Die #pragma-Befehle können nur an zwei verschiedenen Stellen im
  Quelltext eingesetzt werden: Entweder in der obersten Ebene (Top Level) vor der ersten
  Deklaration oder innerhalb eines Blockes - auch hier vor der ersten Deklaration.
  Im ersten Fall ist der Befehl bis zum Ende des Quelltextes oder bis zu einem erneuten Befehl
  mit dem gleichen Pragma gültig. Liegt der erneute Befehl innerhalb eines Blockes, so
  überlagert dieser erneute Befehl den ersten nur innerhalb des Blockes; nach dem Block
  ist wieder das erste Pragma gültig.
  Im zweiten Fall ist der Befehl bis zum Ende des Blockes oder bis zu einem erneuten Befehl
  mit dem gleichen Pragma gültig.
  Mit C99 wurde zusätzlich auch ein _Pragma-Operator eingeführt.
  Dieser wird während des Präprozessor-Laufes zusammen mit dem Parameter zu einem
  #pragma-Befehl umgewandelt.
  Beispiel:
  Die Zeile
  
  _Pragma("STDC FENV_ACCESS ON")
  wird während des Präprozessor-Laufes umgewandelt in
  
  #pragma STDC FENV_ACCESS ON
  Im Gegensatz zum #pragma-Befehl kann der
  _Pragma-Operator durch Makros erstellt werden.
  
10.12. #error
  Der Präprozessor-Befehl #error wurde erst mit dem Standard-C
  eingeführt. Der Befehl erzeugt eine Fehlermeldung während des Compilierens, d.h.
  das Programm kann dadurch nicht compiliert werden. Die Fehlermeldung, die ausgegeben werden
  soll, muss hinter dem Befehl angegeben werden.
  Beispiel:
  
  #ifndef Labelname
  #error Labelname ist nicht definiert!
  #endif
  In diesem Beispiel wird während des Compilierens die Compiler-Fehlermeldung
  "Labelname ist nicht definiert!" ausgegeben, sofern Labelname nicht
  definiert ist. Damit kann der #error-Befehl verwendet werden, um
  z.B. Wiedersprüche in der Programmierung zu finden.
  Beispiel:
  
  #define MAX 255
  #if (MAX % 256) != 0
  #error "MAX muss ein Vielfaches von 256 sein!"
  #endif
  In diesem Beispiel ist die Fehlermeldung in Anführungszeichen gesetzt worden, damit das
  Token MAX nicht durch den #define-Befehl durch 255
  ersetzt wird. Die Anführungszeichen werden in der Fehlermeldung mit ausgegeben.
  
  Voriges Kapitel: 9. Funktionen
  
Nächstes Kapitel: 11. Datei-Ein- und Ausgabe in C

