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

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

Grammatik

bedingungsbedingte :
if-part elif-partsopt else-partopt endif-line

if-part :
If-Line-Text

if-line :
#if Konstantenausdruck
#ifdef-ID
#ifndef-ID

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

elif-line :
#elif Konstantenausdruck

else-part :
Else-Line-Text

else-line :
#else

endif-line :
#endif

Hinweise

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

Die Direktiven #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 vorhergehenden #if Direktive.

Alle Richtlinien zur bedingten Kompilierung, z . B. #if und #ifdef, müssen mit einer schließenden #endif Direktive vor dem Ende der Datei ü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.

Die Makroersetzung erfolgt innerhalb des Teils der Zeile, der einem #elif Befehl folgt, sodass ein Makroaufruf im Konstantenausdruck verwendet werden kann.

Der Vorprozessor 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 handelt es sich um Programmtext, der für den Compiler oder den Präprozessor Bedeutung hat.

Der Präprozessor verarbeitet den ausgewählten 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 der konstante Ausdruck nach jedem #if oder #elif Direktive ausgewertet wird, bis ein wahrer (nonzero)-Konstantenausdruck gefunden wird. Er markiert den gesamten Text (einschließlich anderer Präprozessordirektiven, beginnend mit #) bis zu den zugeordneten #elif, #else oder #endif.

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

Der Konstantenausdruck ist ein ganzzahliger Konstantenausdruck mit den folgenden zusätzlichen Einschränkungen:

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

  • Der Ausdruck kann weder einen Typ-Cast-Operator verwenden sizeof noch einen Operator verwenden.

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

  • Die Übersetzung stellt int die gleiche Art wie Typ longdar, und unsigned int die gleiche Weise wie unsigned long.

  • 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 ermitteln, 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 Konstantenausdrücken verwendet werden, wie in der folgenden Syntax dargestellt:

defined( Identifier )
Definierter Bezeichner

Dieser Konstantenausdruck wird als wahr (nonzero) betrachtet, 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 einer #if und einer #elif-Direktive verwendet werden, sonst aber nirgends.

Im folgenden Beispiel steuern die direktiven #if und #endif 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. Beide und CREDIT credit unterschiedliche Bezeichner in C und C++ sind, da ihre 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 Direktiven 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 eine von vier Auswahlmöglichkeiten basierend auf dem Wert von DLEVEL . 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++ werden Klassen häufig in Headerdateien definiert, Konstrukte wie diese können 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 ja, wurde 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