dyrektywy #if, #elif, #else i #endif (C/C++)

Dyrektywa #if zawierająca dyrektywy #elif, #else i #endif kontroluje kompilację fragmentów pliku źródłowego. Jeśli wyrażenie pisane (po #if) ma wartość niezerową, grupa wierszy bezpośrednio po dyrektywie #if jest przechowywana w jednostce tłumaczenia.

Gramatyka

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

if-part :
tekst w wierszu if

if-line :
#if wyrażenie-stałe
identyfikator #ifdef
identyfikator #ifndef

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

elif-line :
#elif wyrażenie-stałe

else-part :
tekst w innym wierszu

else-line :
#else

endif-line :
#endif

Uwagi

Każda dyrektywa #if w pliku źródłowym musi być zgodna z dyrektywą #endif zamykającą. Dowolna liczba dyrektyw #elif może występować między dyrektywami #if i #endif, ale dozwolona jest co najwyżej jedna dyrektywa #else. Dyrektywa #else , jeśli istnieje, musi być ostatnią dyrektywą przed #endif.

Dyrektywy #if, #elif, #else i #endif mogą zagnieżdżać fragmenty tekstu innych dyrektyw #if . Każda zagnieżdżona dyrektywa #else, #elif lub #endif należy do najbliższej poprzedniej dyrektywy #if .

Wszystkie dyrektywy kompilacji warunkowej, takie jak #if i #ifdef, muszą być zgodne z dyrektywą #endif zamykającą przed końcem pliku. W przeciwnym razie jest generowany komunikat o błędzie. Gdy dyrektywy kompilacji warunkowej są zawarte w plikach dołączanych, muszą spełniać te same warunki: na końcu pliku dołączania nie musi być żadnych niezgodnych dyrektyw kompilacji warunkowej.

Zamiana makr jest wykonywana w części wiersza, która jest zgodna z #elif polecenia, więc w wyrażeniu stałym można użyć wywołania makra.

Preprocesor wybiera jedno z podanych wystąpień tekstu do dalszego przetwarzania. Blok określony w tekście może być dowolną sekwencją tekstu. Może zajmować więcej niż jedną linię. Zazwyczaj tekst jest tekstem programu, który ma znaczenie dla kompilatora lub preprocesora.

Preprocesor przetwarza zaznaczony tekst i przekazuje go do kompilatora. Jeśli tekst zawiera dyrektywy preprocesora, preprocesor wykonuje te dyrektywy. Kompilowane są tylko bloki tekstowe wybrane przez preprocesor.

Preprocesor wybiera pojedynczy element tekstowy , oceniając wyrażenie stałe po każdej dyrektywie #if lub #elif , dopóki nie znajdzie wyrażenia stałej true (nonzero). Wybiera cały tekst (w tym inne dyrektywy preprocesora rozpoczynające się #od ) do skojarzonych #elif, #else lub #endif.

Jeśli wszystkie wystąpienia wyrażenia stałego są fałszywe lub jeśli nie zostaną wyświetlone żadne dyrektywy #elif, preprocesor wybiera blok tekstowy po klauzuli #else. Jeśli nie ma klauzuli #else, a wszystkie wystąpienia wyrażenia stałego w bloku #if są fałszywe, nie jest zaznaczony żaden blok tekstowy.

Wyrażenie stałe jest wyrażeniem stałej liczby całkowitej z następującymi dodatkowymi ograniczeniami:

  • Wyrażenia muszą mieć typ całkowity i mogą zawierać tylko stałe całkowite, stałe znaków i zdefiniowany operator.

  • Wyrażenie nie może użyć sizeof ani operatora rzutowania typu.

  • Środowisko docelowe może nie reprezentować wszystkich zakresów liczb całkowitych.

  • Tłumaczenie reprezentuje typ int w taki sam sposób, jak typ long, i unsigned int tak samo jak unsigned long.

  • Tłumacz może tłumaczyć stałe znaków na zestaw wartości kodu różnić się od zestawu dla środowiska docelowego. Aby określić właściwości środowiska docelowego, użyj aplikacji utworzonej dla tego środowiska, aby sprawdzić wartości limitów. Makra H .

  • Wyrażenie nie może wykonywać zapytań względem środowiska i musi pozostać odizolowane od szczegółów implementacji na komputerze docelowym.

Operatory preprocesora

Definicja

Zdefiniowany operator preprocesora może być używany w specjalnych wyrażeniach stałych, jak pokazano w następującej składni:

defined(identifier)
zdefiniowanyidentyfikator

To wyrażenie stałe jest uznawane za prawdziwe (niezerowe), jeśli identyfikator jest obecnie zdefiniowany. W przeciwnym razie warunek ma wartość false (0). Identyfikator zdefiniowany jako pusty tekst jest uznawany za zdefiniowany. Zdefiniowany operator może być używany w #if i dyrektywie #elif, ale nigdzie indziej.

W poniższym przykładzie dyrektywy #if i #endif kontrolują kompilację jednej z trzech wywołań funkcji:

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

Wywołanie funkcji do credit jest kompilowane, jeśli jest zdefiniowany identyfikator CREDIT . Jeśli identyfikator DEBIT jest zdefiniowany, wywołanie funkcji jest debit kompilowane. Jeśli żaden z identyfikatorów nie jest zdefiniowany, wywołanie metody printerror jest kompilowane. Zarówno identyfikatory, jak CREDIT i credit są odrębnymi identyfikatorami w językach C i C++, ponieważ ich przypadki są różne.

Instrukcje kompilacji warunkowej w poniższym przykładzie zakładają wcześniej zdefiniowaną stałą symboliczną o nazwie DLEVEL.

#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

Pierwszy blok #if przedstawia dwa zestawy zagnieżdżonych dyrektyw #if, #else i #endif . Pierwszy zestaw dyrektyw jest przetwarzany tylko wtedy, gdy DLEVEL > 5 ma wartość true. W przeciwnym razie instrukcje po #else są przetwarzane.

Dyrektywy #elif i #else w drugim przykładzie służą do dokonywania jednej z czterech opcji na podstawie wartości DLEVEL. Stała STACK jest ustawiona na 0, 100 lub 200 w zależności od definicji DLEVEL. Jeśli DLEVEL wartość jest większa niż 5, instrukcja

#elif DLEVEL > 5
display(debugptr);

jest kompilowany i STACK nie jest zdefiniowany.

Typowym zastosowaniem kompilacji warunkowej jest zapobieganie wielokrotnym dołączaniu tego samego pliku nagłówka. W języku C++, gdzie klasy są często definiowane w plikach nagłówkowych, konstrukcje takie jak ten mogą służyć do zapobiegania wielu definicjom:

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

class Example
{
    //...
};

#endif // !defined( EXAMPLE_H )

Powyższy kod sprawdza, czy jest zdefiniowana stała EXAMPLE_H symboliczna. Jeśli tak, plik został już dołączony i nie wymaga ponownego przetwarzania. Jeśli nie, stała EXAMPLE_H jest zdefiniowana do oznaczania EXAMPLE. H jako już przetworzone.

__has_include

Program Visual Studio 2017 w wersji 15.3 lub nowszej: określa, czy nagłówek biblioteki jest dostępny do dołączania:

#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

Zobacz też

Dyrektywy preprocesora