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 Liefert eine 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   /* sucht Datei, die durch
                        den Makronamen
                        angegeben ist          */

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 eine Marke definiert werden. Dazu wird der Befehl #define Marke verwendet. Diese Marke kann der Präprozessor abfragen, ob sie 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 Marke (Abkürzung für #if defined) durchgeführt. Ist die Marke definiert, werden alle folgenden Anweisungen bis zum #else oder #endif mit compiliert, ansonsten nicht. Um nun die Fehlersuche abzuschließen, braucht nur die Definition der Marke gelöscht oder auskommentiert zu werden. Wird sie nur auskommentiert, kann sie 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

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 die Marke Test (der Name der Marke ist beliebig!) definiert. Im Verlauf des Programms wird diese Marke abgefragt, um den Inhalt der Variablen anzeigen zu lassen. Ist dagegen die Marke nicht definiert, wird das Ergebnis der Berechnung angezeigt.

Entsprechend umgekehrt wird mit dem Befehl #ifndef Marke (Abkürzung für #if not defined) geprüft, ob die Marke (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 eine bestimmte Marke bereits definiert ist. Ist dies nicht der Fall (nämlich beim ersten Durchlauf), wird diese Marke definiert. Dann folgen alle Deklarationen und Definitionen der Header-Datei und am Ende das #endif. Wird diese Header-Datei ein weiteres Mal eingelesen, ist die Marke 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 der Marke, die 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 Marken 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 der Marke - z.B. als Variable - durch "nichts" ersetzt werden. Um dies zu verhindern, wird der Name der Marke 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

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

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

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__ Liefert die Zahl 199409L, wenn sich der Compiler nach dem C95-Standard richtet; die Zahl 199901L, wenn sich der Compiler nach dem C99-Standard richtet. Ansonsten ist dieses Makro nicht definiert.

Beispiel:

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    return 0;
18 }

Dieses Beispielprogramm gibt folgendes aus (wenn es in der Quellcodedatei kap10_05.c gespeichert ist und am 19.09.2006 um 22:10:32 Uhr mit einem Standard-C-Compiler compiliert wurde):

Programm wurde compiliert am Sep 19 2006 um 22:10:32.
Diese Programmzeile steht in Zeile 9 in der Datei kap10_05.c.
Standard-C-Compiler!

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:

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 eine Marke bzw. ein Makro wieder zu entfernen. Dazu muss hinter dem Befehl der Name der Marke 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 eine Marke bzw. ein Makro erst einmal entfernt, kann anschließend eine neue Marke 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 Marken 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

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

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.