Namespaces
Variants

Conditional inclusion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Preprocessor
#if #ifdef #ifndef #else #elif #elifdef #elifndef #endif
(C++23) (C++23)
(C++26)

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:

  • __has_include Ausdrücke, die prüfen, ob eine Header- oder Quelldatei existiert.
  • __has_cpp_attribute Ausdrücke, die prüfen, ob ein bestimmtes Attribut-Token unterstützt wird und dessen unterstützte Version.
(seit C++20)
  • __has_embed Ausdrücke, die prüfen, ob eine Ressource zum Einbetten verfügbar ist.
(seit C++26)

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 .

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

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