direktivy #if, #elif, #else a #endif (C/C++)
Direktiva #if s direktivami #elif, #else a #endif řídí kompilaci částí zdrojového souboru. Pokud má výraz, který napíšete (za #if), nenulovou hodnotu, skupina řádků bezprostředně za direktivou #if se uchovává v jednotce překladu.
Gramatika
podmíněný :
if-part elif-partsopt else-partopt-line
if-part :
If-line text
if-line :
#if výraz konstanty
identifikátor #ifdef
identifikátor #ifndef
elif-parts :
elif-line text
elif-parts elif-line text
elif-line :
#elif výraz konstanty
else-part :
else-line text
else-line :
#else
endif-line :
#endif
Poznámky
Každá direktiva #if ve zdrojovém souboru musí odpovídat koncové direktivě #endif. Mezi direktivy #if a #endif se může objevit libovolný počet direktiv #elif, ale je povolena maximálně jedna direktiva #else. #else směrnice, 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á #else, #elif nebo direktiva #endif patří k nejbližší předchozí direktivě #if.
Všechny direktivy podmíněné kompilace, například #if a #ifdef, musí odpovídat závěru #endif direktivě 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 include, musí splňovat stejné podmínky: Na konci souboru include nesmí existovat žádné direktivy podmíněné kompilace.
Nahrazení makra se provádí v rámci řá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, preprocesor provede tyto direktivy. Kompilují se pouze textové bloky vybrané preprocesorem.
Preprocesor vybere jednu textovou položku vyhodnocením konstantního výrazu za každým #if nebo direktivou #elif, dokud nenajde skutečný (nenulový) konstantní výraz. Vybere veškerý text (včetně jiných direktiv preprocesoru začínajících #) až do přidružených #elif, #else nebo #endif.
Pokud jsou všechny výskyty konstantního výrazu false nebo pokud se nezobrazí žádné direktivy #elif, preprocesor vybere blok textu za klauzulí #else. Pokud neexistuje žádná klauzule #else a všechny instance konstantního výrazu v bloku #if jsou nepravdivé, není vybraný žádný blok textu.
Výraz konstanty je celočíselná konstanta výraz s těmito další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
ani operátor přetypování typu.Cílové prostředí nemusí představovat všechny rozsahy celých čísel.
Překlad představuje typ
int
stejně jako typlong
aunsigned int
stejný jakounsigned long
.Translator 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
Operátor preprocesoru definovaný lze použít ve speciálních konstantních výrazech, jak je znázorněno následující syntaxí:
defined( identifier )
definovaný identifikátor
Tento konstantní výraz je považován za pravdivý (nenulový), pokud je identifikátor aktuálně definován. 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 direktivě #elif, ale nikde jinde.
V následujícím příkladu řídí direktivy #if a #endif kompilaci jednoho ze tří volání funkce:
#if defined(CREDIT)
credit();
#elif defined(DEBIT)
debit();
#else
printerror();
#endif
Volání funkce credit
je zkompilováno, pokud je definován identifikátor CREDIT
. Pokud je identifikátor DEBIT
definován, volání debit
funkce je zkompilováno. Pokud není definován žádný identifikátor, volání printerror
se zkompiluje. V jazyce C a credit
C++ jsou jedinečné CREDIT
identifikátory, protože jejich případy jsou odlišné.
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
je true. V opačném případě se příkazy po #else zpracovávají.
Direktivy #elif a #else v druhém příkladu slouží k provedení jedné ze čtyř voleb na základě hodnoty DLEVEL
. Konstanta STACK
je nastavena na 0, 100 nebo 200 v závislosti na definici DLEVEL
. Pokud DLEVEL
je větší než 5, pak příkaz
#elif DLEVEL > 5
display(debugptr);
je zkompilován a STACK
není definován.
Běžným použitím podmíněné kompilace je zabránit více zahrnutí stejného souboru hlaviček. V jazyce C++, kde jsou třídy často definovány v souborech hlaviček, lze konstrukty podobné této použít k zabránění 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, je konstanta EXAMPLE_H
definována tak, aby označí příklad. H jako již zpracováno.
__has_include
Visual Studio 2017 verze 15.3 a novější: Určuje, jestli je hlavička knihovny k dispozici 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