Conditional inclusion
Der Präprozessor unterstützt die bedingte Kompilierung von Teilen einer Quelldatei. Dieses Verhalten wird gesteuert durch die Direktiven
#if
,
#else
,
#elif
,
#ifdef
,
#ifndef
,
#elifdef
,
#elifndef
(seit C++23)
und
#endif
.
Inhaltsverzeichnis |
Syntax
#if
Ausdruck
|
|||||||||
#ifdef
Bezeichner
|
|||||||||
#ifndef
Bezeichner
|
|||||||||
#elif
Ausdruck
|
|||||||||
#elifdef
Bezeichner
|
(seit C++23) | ||||||||
#elifndef
Bezeichner
|
(seit C++23) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
Erklärung
Der bedingte Präprozessorblock beginnt mit der
#if
-,
#ifdef
- oder
#ifndef
-Direktive, enthält optional beliebig viele
#elif
-,
#elifdef
- oder
#elifndef
(seit C++23)
-Direktiven, enthält optional höchstens eine
#else
-Direktive und wird mit der
#endif
-Direktive abgeschlossen. Alle inneren bedingten Präprozessorblöcke werden separat verarbeitet.
Jede der
#if
-,
#ifdef
-,
#ifndef
-,
#elif
-,
#elifdef
-,
#elifndef
(seit C++23)
- und
#else
-Direktiven steuert den Codeblock bis zur ersten
#elif
-,
#elifdef
-,
#elifndef
(seit C++23)
-,
#else
-,
#endif
-Direktive, die nicht zu inneren bedingten Präprozessorblöcken gehört.
#if
-,
#ifdef
- und
#ifndef
-Direktiven testen die angegebene Bedingung (siehe unten) und falls diese als wahr ausgewertet wird, kompilieren sie den kontrollierten Codeblock. In diesem Fall werden nachfolgende
#else
-,
#elifdef
-,
#elifndef
-
(seit C++23)
und
#elif
-Direktiven ignoriert. Andernfalls, falls die angegebene Bedingung als falsch ausgewertet wird, wird der kontrollierte Codeblock übersprungen und die nachfolgende
#else
-,
#elifdef
-,
#elifndef
-
(seit C++23)
oder
#elif
-Direktive (falls vorhanden) verarbeitet. Falls die nachfolgende Direktive
#else
ist, wird der durch die
#else
-Direktive kontrollierte Codeblock bedingungslos kompiliert. Andernfalls verhält sich die
#elif
-,
#elifdef
- oder
#elifndef
(seit C++23)
-Direktive wie eine
#if
-Direktive: Sie prüft die Bedingung, kompiliert oder überspringt den kontrollierten Codeblock basierend auf dem Ergebnis und verarbeitet im letzteren Fall nachfolgende
#elif
-,
#elifdef
-,
#elifndef
-
(seit C++23)
und
#else
-Direktiven. Der bedingte Präprozessorblock wird durch die
#endif
-Direktive beendet.
Bedingungsauswertung
#if, #elif
Ausdruck
kann unäre Operatoren in der Form
defined
Bezeichner
oder
defined (
Bezeichner
)
enthalten. Das Ergebnis ist
1
wenn der
Bezeichner
als
Makroname definiert wurde
, andernfalls ist das Ergebnis
0
.
|
expression kann auch die folgenden Ausdrücke enthalten:
Die oben genannten Bezeichner werden in diesem Kontext so behandelt, als wären sie Namen definierter Makros. |
(seit C++17) |
Nachdem alle Makro-Erweiterungen und Auswertungen von
defined
und den oben beschriebenen Ausdrücken abgeschlossen sind, wird jeder Bezeichner, der kein
boolean literal
ist, durch die Zahl
0
ersetzt (dies schließt Bezeichner ein, die lexikalisch Schlüsselwörter sind, aber nicht alternative Tokens wie
and
).
Dann wird der Ausdruck als ein integral constant expression ausgewertet.
Wenn der Ausdruck einen Wert ungleich Null ergibt, wird der kontrollierte Codeblock eingeschlossen und andernfalls übersprungen.
Hinweis: Bis zur Lösung von
CWG Issue 1955
unterscheidet sich
#if
cond1
...
#elif
cond2
von
#if
cond1
...
#else
gefolgt von
#if
cond2
, denn falls
cond1
wahr ist, wird das zweite
#if
übersprungen und
cond2
muss nicht wohlgeformt sein, während
#elif
's
cond2
ein gültiger Ausdruck sein muss. Seit CWG 1955 wird auch
#elif
übersprungen, das zu einem übersprungenen Codeblock führt.
Kombinierte Direktiven
Prüft, ob der Bezeichner als Makroname definiert wurde.
#ifdef
identifier
ist im Wesentlichen gleichbedeutend mit
#if defined
identifier
.
#ifndef
identifier
ist im Wesentlichen gleichbedeutend mit
#if !defined
identifier
.
|
|
(seit C++23) |
Hinweise
Während die Direktiven
#elifdef
und
#elifndef
auf C++23 abzielen, werden Implementierungen ermutigt, sie als konforme Erweiterungen auf ältere Sprachmodi zurückzuportieren.
Beispiel
#define ABCD 2 #include <iostream> int main() { #ifdef ABCD std::cout << "1: yes\n"; #else std::cout << "1: no\n"; #endif #ifndef ABCD std::cout << "2: no1\n"; #elif ABCD == 2 std::cout << "2: yes\n"; #else std::cout << "2: no2\n"; #endif #if !defined(DCBA) && (ABCD < 2*4-3) std::cout << "3: yes\n"; #endif // Beachten Sie, dass wenn ein Compiler die #elifdef/#elifndef-Direktiven // von C++23 nicht unterstützt, dann wird der "unerwartete" Block (siehe unten) ausgewählt. #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // erwarteter Block #else std::cout << "4: no!\n"; // wählt unerwartet diesen Block aus, indem // unbekannte Direktiven übersprungen werden und direkt // von "#ifdef CPU" zu diesem "#else"-Block "gesprungen" wird #endif // Um das obige Problem zu beheben, können wir das Makro ELIFDEF_SUPPORTED // nur dann bedingt definieren, wenn die C++23-Direktiven // #elifdef/#elifndef unterstützt werden. #if 0 #elifndef UNDEFINED_MACRO #define ELIFDEF_SUPPORTED #else #endif #ifdef ELIFDEF_SUPPORTED #ifdef CPU std::cout << "4: no1\n"; #elifdef GPU std::cout << "4: no2\n"; #elifndef RAM std::cout << "4: yes\n"; // erwarteter Block #else std::cout << "4: no3\n"; #endif #else // wenn #elifdef nicht unterstützt wird, verwende die alte ausführliche "#elif defined"-Syntax #ifdef CPU std::cout << "4: no1\n"; #elif defined GPU std::cout << "4: no2\n"; #elif !defined RAM std::cout << "4: yes\n"; // erwarteter Block #else std::cout << "4: no3\n"; #endif #endif }
Mögliche Ausgabe:
1: yes 2: yes 3: yes 4: no! 4: yes
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 1955 | C++98 | fehlgeschlagene #elif -Ausdrücke mussten gültig sein | fehlgeschlagene #elif werden übersprungen |
Siehe auch
|
C-Dokumentation
für
Bedingte Einschlussdirektive
|