#if-, #elif-, #else- und #endif-Anweisungen (C/C++)

Die #if-Direktive mit den #elif-, #else- und #endif-Direktiven steuert die Kompilierung von Teilen einer Quelldatei. Wenn der Von Ihnen geschriebene Ausdruck (nach dem #if) einen Wert ungleich null aufweist, wird die Zeilengruppe, die unmittelbar auf die #if-Direktive folgt, in der Übersetzungseinheit beibehalten.

Grammatik

bedingt :
if-part elif-partsoptelse-partoptendif-line

if-part :
if-line text

if-line :
#ifkonstanten Ausdruck
#ifdefBezeichner
#ifndef-Id

elif-parts :
elif-line text
elif-parts elif-line text

elif-line :
#elifkonstanten Ausdruck

else-part :
else-line text

else-line :
#else

endif-line :
#endif

Bemerkungen

Jede #if-Direktive in einer Quelldatei muss durch eine schließende #endif-Direktive abgeglichen werden. Zwischen den #if- und#endif-Direktiven kann eine beliebige Anzahl von #elif-Direktiven angezeigt werden, aber höchstens eine #else-Direktive ist zulässig. Die #else-Direktive muss, sofern vorhanden, die letzte Direktive vor #endif sein.

Die Anweisungen #if, #elif, #else und #endif können in den Textabschnitten anderer #if-Direktiven geschachtelt werden. Jede geschachtelte #else-, #elif- oder #endif-Direktive gehört zur nächstgelegenen vorangehenden #if-Direktive.

Alle Anweisungen für die bedingte Kompilierung, z. B. #if und #ifdef, müssen vor dem Ende der Datei mit einer schließenden #endif-Anweisung übereinstimmen. Andernfalls wird eine Fehlermeldung generiert. Wenn Includedateien bedingte Kompilierungsanweisungen enthalten, müssen sie die gleichen Bedingungen erfüllen: Am Ende der Includedatei dürfen sich keine bedingten Kompilierungsanweisungen ohne Entsprechung befinden.

Makroersetzung erfolgt innerhalb des Teils der Zeile, der auf einen #elif Befehl folgt, sodass ein Makroaufruf im constant-expression verwendet werden kann.

Der Präprozessor wählt eines der angegebenen Vorkommen von Text zur weiteren Verarbeitung aus. Ein in Text angegebener Block kann eine beliebige Textsequenz sein. Er kann mehr als eine Zeile umfassen. In der Regel ist Text Programmtext, der für den Compiler oder den Präprozessor Bedeutung hat.

Der Präprozessor verarbeitet den markierten Text und übergibt ihn an den Compiler. Wenn Text Präprozessordirektiven enthält, führt der Präprozessor diese Direktiven aus. Nur Textblöcke, die vom Präprozessor ausgewählt werden, werden kompiliert.

Der Präprozessor wählt ein einzelnes Textelement aus, indem er den konstanten Ausdruck nach jeder #if - oder #elif-Direktive aus wertet, bis er einen true -Konstantenausdruck (ungleich null) findet. Er wählt den gesamten Text (einschließlich anderer Präprozessordirektiven beginnend mit #) bis zum zugeordneten #elif, #else oder #endif aus.

Wenn alle Vorkommen von constant-expression false sind oder keine #elif-Anweisungen angezeigt werden, markiert der Präprozessor den Textblock nach der #else-Klausel . Wenn keine #else-Klausel vorhanden ist und alle Instanzen von constant-expression im #if-Block false sind, wird kein Textblock ausgewählt.

Der Constant-Expression ist ein ganzzahliger konstanter Ausdruck mit den folgenden zusätzlichen Einschränkungen:

  • Ausdrücke müssen einen integralen Typ aufweisen und dürfen nur ganzzahlige Konstanten, Zeichenkonstanten und den definierten Operator enthalten.

  • Der Ausdruck kann oder keinen Typumwandlungsoperator verwenden sizeof .

  • Die Zielumgebung kann möglicherweise nicht alle Bereiche von ganzen Zahlen darstellen.

  • Die Übersetzung stellt den Typ int auf die gleiche Weise wie den Typ longund unsigned int auf die gleiche Weise wie unsigned longdar.

  • Das Konvertierungsprogramm kann Zeichenkonstanten in einen Satz von Codewerten übersetzen, die sich vom Satz für die Zielumgebung unterscheiden. Um die Eigenschaften der Zielumgebung zu bestimmen, verwenden Sie eine app, die für diese Umgebung erstellt wurde, um die Werte der LIMITS zu überprüfen . H-Makros .

  • Der Ausdruck darf die Umgebung nicht abfragen und muss von Implementierungsdetails auf dem Zielcomputer isoliert bleiben.

Präprozessor-Operatoren

definiert

Der definierte Präprozessoroperator kann in speziellen konstanten Ausdrücken verwendet werden, wie in der folgenden Syntax gezeigt:

defined(identifier)
DefinierterBezeichner

Dieser konstante Ausdruck gilt als true (ungleich null), wenn der Bezeichner derzeit definiert ist. Andernfalls ist die Bedingung "false" (0). Ein Bezeichner, der als leerer Text definiert wird, wird als definiert betrachtet. Der definierte Operator kann in einem #if und einer #elif-Direktive verwendet werden, aber nirgendwo sonst.

Im folgenden Beispiel steuern die #if - und #endif-Anweisungen die Kompilierung eines von drei Funktionsaufrufen:

#if defined(CREDIT)
    credit();
#elif defined(DEBIT)
    debit();
#else
    printerror();
#endif

Der Funktionsaufruf an credit wird kompiliert, wenn der Bezeichner CREDIT definiert ist. Wenn der Bezeichner DEBIT definiert ist, wird der Funktionsaufruf an debit kompiliert. Wenn keiner der Bezeichner definiert ist, wird der Aufruf an printerror kompiliert. Sowohl als credit auch CREDIT sind unterschiedliche Bezeichner in C und C++, da die Fälle unterschiedlich sind.

Die Anweisungen für die bedingte Kompilierung im folgenden Beispiel gehen von einer zuvor definierten symbolischen Konstante aus, die DLEVEL heißt.

#if DLEVEL > 5
    #define SIGNAL  1
    #if STACKUSE == 1
        #define STACK   200
    #else
        #define STACK   100
    #endif
#else
    #define SIGNAL  0
    #if STACKUSE == 1
        #define STACK   100
    #else
        #define STACK   50
    #endif
#endif
#if DLEVEL == 0
    #define STACK 0
#elif DLEVEL == 1
    #define STACK 100
#elif DLEVEL > 5
    display( debugptr );
#else
    #define STACK 200
#endif

Der erste #if-Block zeigt zwei Sätze geschachtelter #if, #else und #endif-Anweisungen an. Der erste Satz von Direktiven wird nur verarbeitet, wenn DLEVEL > 5 "true" ist. Andernfalls werden die Anweisungen nach #else verarbeitet.

Die #elif - und #else-Direktiven im zweiten Beispiel werden verwendet, um basierend auf dem Wert von DLEVELeine von vier Optionen zu treffen. Die Konstante STACK ist auf 0, 100 oder 200 festgelegt, abhängig von der Definition von DLEVEL. Wenn DLEVEL größer als 5 ist, wird die Anweisung

#elif DLEVEL > 5
display(debugptr);

wird kompiliert und STACK ist nicht definiert.

Eine übliche Verwendung für die bedingte Kompilierung besteht darin, mehrere Inklusionen derselben Headerdatei zu verhindern. In C++, wo Klassen häufig in Headerdateien definiert werden, können Konstrukte wie diese verwendet werden, um mehrere Definitionen zu verhindern:

/*  EXAMPLE.H - Example header file  */
#if !defined( EXAMPLE_H )
#define EXAMPLE_H

class Example
{
    //...
};

#endif // !defined( EXAMPLE_H )

Der vorangehende Code überprüft, ob die symbolische Konstante EXAMPLE_H definiert ist. Wenn dies der Fall ist, ist die Datei bereits enthalten und muss nicht erneut verarbeitet werden. Wenn dies nicht der Fall ist, wird die Konstante EXAMPLE_H definiert, um EXAMPLE.H als bereits verarbeitet zu markieren.

__has_include

Visual Studio 2017, Version 15.3 und höher: Bestimmt, ob ein Bibliotheksheader zur Aufnahme verfügbar ist:

#ifdef __has_include
#  if __has_include(<filesystem>)
#    include <filesystem>
#    define have_filesystem 1
#  elif __has_include(<experimental/filesystem>)
#    include <experimental/filesystem>
#    define have_filesystem 1
#    define experimental_filesystem
#  else
#    define have_filesystem 0
#  endif
#endif

Siehe auch

Präprozessoranweisungen