Namensräume
Varianten
Aktionen

Bedingte Einbindung

Von cppreference.com

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 __has_c_attribute-Ausdruck, ob ein bestimmtes Attribut-Token unterstützt wird und welche Version davon unterstützt wird. Siehe Attributprüfung.

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

#elifdef Bezeichner ist im Wesentlichen äquivalent zu #elif defined Bezeichner.

#elifndef Bezeichner ist im Wesentlichen äquivalent zu #elif ! 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