direktivy #if, #elif, #else a #endif (C/C++)
Direktiva #if s direktivami #elif, #else a #endif řídí kompilaci částí zdrojového souboru. Pokud má zapsaný výraz (za #if) nenulovou hodnotu, skupina řádků bezprostředně za direktivou #if zůstane v jednotce překladu.
Gramatika
podmíněné :
if-part elif-partsoptelse-partoptendif-line
if-part :
if-line text
if-line :
#ifvýraz konstanty
identifikátor #ifdef
identifikátor #ifndef
elif-parts :
elif-line text
elif-parts elif-line text
elif-line :
#elifvýraz konstanty
else-part :
text jiného řádku
else-line :
#else
endif-line :
#endif
Poznámky
Každá direktiva #if ve zdrojovém souboru musí odpovídat uzavírací direktivě #endif . Mezi direktivou #if a #endif se může objevit libovolný počet direktiv #elif, ale nejvýše jedna direktiva #else je povolena. Direktiva #else, pokud existuje, musí být poslední direktivou před #endif.
Direktivy #if, #elif, #else a #endif mohou vnořit do textových částí jiných direktiv #if. Každá vnořená direktiva #else, #elif nebo #endif patří k nejbližší předchozí direktivě #if .
Všechny direktivy podmíněné kompilace, například #if a #ifdef, musí odpovídat uzavírací direktivě #endif před koncem souboru. V opačném případě se vygeneruje chybová zpráva. Pokud jsou direktivy podmíněné kompilace obsaženy v souborech zahrnutí, musí splňovat stejné podmínky: Na konci souboru zahrnutí nesmí být žádné direktivy podmíněné kompilace.
Nahrazení makra se provádí v rámci části řádku, která následuje za příkazem #elif , takže volání makra lze použít ve výrazu konstanty.
Preprocesor vybere jeden z daných výskytů textu pro další zpracování. Blok zadaný v textu může být libovolná posloupnost textu. Může zabírat více než jeden řádek. Text je obvykle text programu, který má význam pro kompilátor nebo preprocesor.
Preprocesor zpracuje vybraný text a předá ho kompilátoru. Pokud text obsahuje direktivy preprocesoru, provede preprocesor tyto direktivy. Kompilují se pouze textové bloky vybrané preprocesorem.
Preprocesor vybere jednu textovou položku tak, že vyhodnotí konstantní výraz následující za každou #if nebo #elif direktivu, dokud nenajde pravdivý (nenulový) konstantní výraz. Vybere veškerý text (včetně jiných direktiv preprocesoru začínající #na ) až po přidružené #elif, #else nebo #endif.
Pokud jsou všechny výskyty konstanty výrazu false nebo pokud se nezobrazí žádné direktivy #elif , preprocesor vybere blok textu za klauzulí #else . Pokud není k dispozici žádná #else klauzule a všechny instance konstantního výrazu v bloku #if mají hodnotu false, nebude vybrán žádný blok textu.
Výraz konstanty je celočíselný konstantní výraz s těmito dodatečnými omezeními:
Výrazy musí mít celočíselný typ a mohou obsahovat pouze celočíselné konstanty, znakové konstanty a definovaný operátor.
Výraz nemůže použít
sizeof
operátor přetypování typu nebo .Cílové prostředí nemusí představovat všechny rozsahy celých čísel.
Překlad představuje typ
int
stejným způsobem jako typlong
aunsigned int
stejným způsobem jakounsigned long
.Překladatel může přeložit znakové konstanty na sadu hodnot kódu, které se liší od sady pro cílové prostředí. Pokud chcete určit vlastnosti cílového prostředí, pomocí aplikace vytvořené pro toto prostředí zkontrolujte hodnoty OMEZENÍ. Makra H .
Výraz nesmí dotazovat prostředí a musí zůstat izolovaný od podrobností implementace v cílovém počítači.
Operátory preprocesoru
definováno
Definovaný operátor preprocesoru lze použít ve speciálních konstantních výrazech, jak ukazuje následující syntaxe:
defined(identifikátor)
definovanýidentifikátor
Tento konstantní výraz se považuje za pravdivý (nenulový), pokud je identifikátor aktuálně definovaný. V opačném případě je podmínka false (0). Identifikátor definovaný jako prázdný text se považuje za definovaný. Definovaný operátor lze použít v #if a #elif direktivě, ale nikde jinde.
V následujícím příkladu #if a direktivy #endif řídí kompilaci jednoho ze tří volání funkce:
#if defined(CREDIT)
credit();
#elif defined(DEBIT)
debit();
#else
printerror();
#endif
Volání funkce se credit
zkompiluje, pokud je identifikátor CREDIT
definován. Pokud je identifikátor DEBIT
definovaný, volání funkce se debit
zkompiluje. Pokud není definován ani jeden identifikátor, je volání printerror
zkompilováno. credit
I CREDIT
jsou jedinečné identifikátory v jazyce C a C++, protože jejich případy se liší.
Příkazy podmíněné kompilace v následujícím příkladu předpokládají dříve definovanou symbolickou konstantu s názvem 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
První blok #if zobrazuje dvě sady vnořených #if, #else a direktiv #endif . První sada direktiv je zpracována pouze v případě, že DLEVEL > 5
má hodnotu true. V opačném případě se příkazy po #else zpracují.
Direktivy #elif a #else v druhém příkladu slouží k provedení jedné ze čtyř možností na základě hodnoty DLEVEL
. Konstanta STACK
se nastaví na 0, 100 nebo 200 v závislosti na definici .DLEVEL
Pokud DLEVEL
je větší než 5, příkaz
#elif DLEVEL > 5
display(debugptr);
je zkompilovaný a STACK
není definován.
Běžným použitím podmíněné kompilace je zabránění vícenásobnému zahrnutí stejného souboru hlaviček. V jazyce C++, kde jsou třídy často definovány v souborech hlaviček, lze konstruktorům, jako je tato, zabránit více definic:
/* EXAMPLE.H - Example header file */
#if !defined( EXAMPLE_H )
#define EXAMPLE_H
class Example
{
//...
};
#endif // !defined( EXAMPLE_H )
Předchozí kód zkontroluje, jestli je definovaná symbolická konstanta EXAMPLE_H
. Pokud ano, soubor už je zahrnutý a není potřeba ho znovu zpracovat. Pokud ne, konstanta EXAMPLE_H
je definována pro označení EXAMPLE. H tak, jak je již zpracováno.
__has_include
Visual Studio 2017 verze 15.3 a novější: Určuje, jestli je k dispozici hlavička knihovny pro zahrnutí:
#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