Bedingte Einbindung
Der Präprozessor unterstützt die bedingte Kompilierung von Teilen einer Quelldatei. Dieses Verhalten wird durch die Direktiven #if, #else, #elif, #ifdef, #ifndef, #elifdef, #elifndef(seit C23) und #endif gesteuert.
Inhalt |
[bearbeiten] Syntax
#if Ausdruck |
|||||||||
#ifdef Bezeichner |
|||||||||
#ifndef Bezeichner |
|||||||||
#elif Ausdruck |
|||||||||
#elifdef Bezeichner |
(seit C23) | ||||||||
#elifndef Bezeichner |
(seit C23) | ||||||||
#else
|
|||||||||
#endif
|
|||||||||
[bearbeiten] Erklärung
Der bedingte Präprozessorblock beginnt mit einer #if-, #ifdef- oder #ifndef-Direktive, gefolgt von optional beliebig vielen #elif, #elifdef- oder #elifndef-Direktiven(seit C23), dann optional einer #else-Direktive und wird mit einer #endif-Direktive abgeschlossen. Verschachtelte bedingte Präprozessorblöcke werden separat verarbeitet.
Jede der Direktiven #if, #ifdef, #ifndef, #elif, #elifdef, #elifndef(seit C23) und #else steuert einen Codeblock bis zur ersten #elif, #elifdef, #elifndef(seit C23)-, #else- oder #endif-Direktive, die nicht zu einem inneren bedingten Präprozessorblock gehört.
Die Direktiven #if, #ifdef und #ifndef prüfen die angegebene Bedingung (siehe unten) und kompilieren den gesteuerten Codeblock, wenn diese wahr ist. In diesem Fall werden nachfolgende #else, #elifdef, #elifndef,(seit C23) und #elif-Direktiven ignoriert. Andernfalls, wenn die angegebene Bedingung falsch ist, wird der gesteuerte Codeblock übersprungen und die nachfolgende #else, #elifdef, #elifndef,(seit C23) oder #elif-Direktive (falls vorhanden) verarbeitet. Wenn die nachfolgende Direktive #else ist, wird der von der #else-Direktive gesteuerte Codeblock bedingungslos kompiliert. Andernfalls verhält sich die #elif, #elifdef- oder #elifndef(seit C23)-Direktive wie eine #if-Direktive: Sie prüft die Bedingung, kompiliert oder überspringt den gesteuerten Codeblock basierend auf dem Ergebnis und verarbeitet im letzteren Fall nachfolgende #elif, #elifdef, #elifndef,(seit C23) und #else-Direktiven. Der bedingte Präprozessorblock wird mit der #endif-Direktive beendet.
[bearbeiten] Bedingte Auswertung
[bearbeiten] #if, #elif
Der Ausdruck ist ein konstanter Ausdruck, der nur Konstanten und Bezeichner verwendet, die mit der #define-Direktive definiert wurden. Jeder Bezeichner, der kein Literal und nicht mit der #define-Direktive definiert wurde, wird zu 0 ausgewertet, außer true, das zu 1 ausgewertet wird(seit C23).
Der Ausdruck kann unäre Operatoren in der Form defined Bezeichner oder defined (Bezeichner) enthalten, die 1 zurückgeben, wenn der Bezeichner mit der #define-Direktive definiert wurde, und 0 andernfalls. In diesem Kontext werden __has_include, __has_embed und __has_c_attribute so behandelt, als wären sie Namen von definierten Makros.(seit C23) Wenn der Ausdruck einen von Null verschiedenen Wert ergibt, wird der gesteuerte Codeblock einbezogen, andernfalls übersprungen. Wenn ein verwendeter Bezeichner keine Konstante ist, wird er durch 0 ersetzt.
|
Im Kontext einer Präprozessor-Direktive erkennt ein |
(seit C23) |
Hinweis: Bis zu DR 412 war #if cond1 ... #elif cond2 anders als #if cond1 ... #else gefolgt von #if cond3, da im Falle von cond1 wahr, das zweite #if übersprungen wurde und cond3 nicht wohlgeformt sein musste, während das cond2 von #elif ein gültiger Ausdruck sein musste. Seit DR 412 wird #elif, das zu einem übersprungenen Codeblock führt, ebenfalls übersprungen.
[bearbeiten] Kombinierte Direktiven
Prüft, ob der Bezeichner als Makroname definiert wurde.
#ifdef Bezeichner ist im Wesentlichen äquivalent zu #if defined Bezeichner.
#ifndef Bezeichner ist im Wesentlichen äquivalent zu #if ! defined Bezeichner.
|
|
(seit C23) |
[bearbeiten] Hinweise
Obwohl die Direktiven #elifdef und #elifndef für C23 vorgesehen sind, können Implementierungen sie als konforme Erweiterungen auch in ältere Sprachmodi übernehmen.
[bearbeiten] Beispiel
#define ABCD 2 #include <stdio.h> int main(void) { #ifdef ABCD printf("1: yes\n"); #else printf("1: no\n"); #endif #ifndef ABCD printf("2: no1\n"); #elif ABCD == 2 printf("2: yes\n"); #else printf("2: no2\n"); #endif #if !defined(DCBA) && (ABCD < 2 * 4 - 3) printf("3: yes\n"); #endif // C23 directives #elifdef/#elifndef #ifdef CPU printf("4: no1\n"); #elifdef GPU printf("4: no2\n"); #elifndef RAM printf("4: yes\n"); // selected in C23 mode, may be selected in pre-C23 mode #else printf("4: no3\n"); // may be selected in pre-C23 mode #endif }
Mögliche Ausgabe
1: yes 2: yes 3: yes 4: yes
[bearbeiten] Fehlerberichte
Die folgenden verhaltensändernden Defect Reports wurden rückwirkend auf zuvor veröffentlichte C-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| DR 412 | C89 | Der Ausdruck von #elif musste gültig sein |
#elif wird übersprungen |
[bearbeiten] Referenzen
- C23-Standard (ISO/IEC 9899:2024)
- 6.10.1 Bedingte Einbindung (S. TBD)
- C17-Standard (ISO/IEC 9899:2018)
- 6.10.1 Bedingte Einbindung (S. 118-119)
- C11-Standard (ISO/IEC 9899:2011)
- 6.10.1 Bedingte Einbindung (S. 162-164)
- C99-Standard (ISO/IEC 9899:1999)
- 6.10.1 Bedingte Einbindung (S. 147-149)
- C89/C90-Standard (ISO/IEC 9899:1990)
- 3.8.1 Bedingte Einbindung
[bearbeiten] Siehe auch
| C++ Dokumentation für Bedingte Einbindung
|