Namespaces
Variants

Conditional inclusion

From cppreference.net

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 C23) und #endif .

Inhaltsverzeichnis

Syntax

#if Ausdruck
#ifdef Bezeichner
#ifndef Bezeichner
#elif Ausdruck
#elifdef Bezeichner (seit C23)
#elifndef Bezeichner (seit C23)
#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 C23) -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 C23) - und #else -Direktiven steuert einen Codeblock bis zur ersten #elif -, #elifdef -, #elifndef (seit C23) -, #else - oder #endif -Direktive, die nicht zu inneren bedingten Präprozessorblöcken gehört.

#if , #ifdef und #ifndef -Direktiven testen die angegebene Bedingung (siehe unten) und wenn diese als wahr ausgewertet wird, kompilieren sie den kontrollierten Codeblock. In diesem Fall werden nachfolgende #else , #elifdef , #elifndef , (seit C23) und #elif -Direktiven ignoriert. Andernfalls, wenn die angegebene Bedingung als falsch ausgewertet wird, wird der kontrollierte Codeblock übersprungen und die nachfolgende #else , #elifdef , #elifndef , (seit C23) oder #elif -Direktive (falls vorhanden) wird verarbeitet. Wenn 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 C23) -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 C23) und #else -Direktiven. Der bedingte Präprozessorblock wird durch die #endif -Direktive beendet.

Bedingte Auswertung

#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 ist und nicht mit der #define Direktive definiert wurde, ergibt 0 außer true , was zu 1 ergibt (seit C23) .

Der Ausdruck kann unäre Operatoren in der Form defined identifier oder defined ( identifier ) enthalten, die 1 zurückgeben, falls der identifier mit der #define Direktive definiert wurde, andernfalls 0 . In diesem Kontext werden __has_include , __has_embed und __has_c_attribute so behandelt, als wären sie Namen definierter Makros. (seit C23) Wenn der expression einen Wert ungleich Null ergibt, wird der kontrollierte Codeblock eingeschlossen, andernfalls übersprungen. Falls eine verwendete Kennung keine Konstante ist, wird sie durch 0 ersetzt.

Im Kontext einer Präprozessor-Direktive erkennt ein __has_c_attribute -Ausdruck, ob ein bestimmter Attribut-Token unterstützt wird und dessen unterstützte Version. Siehe Attribut-Test .

(seit C23)

Hinweis: Bis DR 412 unterscheidet sich #if cond1 ... #elif cond2 von #if cond1 ... #else gefolgt von #if cond3 , weil falls cond1 wahr ist, das zweite #if übersprungen wird und cond3 nicht wohlgeformt sein muss, während #elif 's cond2 ein gültiger Ausdruck sein muss. Ab DR 412 wird auch #elif übersprungen, das zum ü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 äquivalent zu #if !defined identifier .

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

#elifndef identifier ist im Wesentlichen äquivalent zu #elif !defined identifier .

(seit C23)

Hinweise

Während die Direktiven #elifdef und #elifndef auf C23 abzielen, können Implementierungen sie als konforme Erweiterungen auf ältere Sprachmodi zurückportieren.

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

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
DR 412 C89 fehlgeschlagene #elif -Ausdrücke mussten gültig sein fehlgeschlagenes #elif wird übersprungen

Referenzen

  • C23-Standard (ISO/IEC 9899:2024):
  • 6.10.1 Bedingte Inklusion (S: TBD)
  • C17-Standard (ISO/IEC 9899:2018):
  • 6.10.1 Bedingte Übersetzung (S: 118-119)
  • C11-Standard (ISO/IEC 9899:2011):
  • 6.10.1 Bedingte Einschließung (S: 162-164)
  • C99-Standard (ISO/IEC 9899:1999):
  • 6.10.1 Bedingte Inklusion (S: 147-149)
  • C89/C90 Standard (ISO/IEC 9899:1990):
  • 3.8.1 Bedingte Einschluss

Siehe auch

C++ Dokumentation für Bedingte Einschlüsse