direttive #if, #elif, #else e #endif (C/C++)

La direttiva #if , con le direttive #elif, #else e #endif , controlla la compilazione di parti di un file di origine. Se l'espressione scritta (dopo la #if) ha un valore diverso da zero, il gruppo di righe immediatamente successivo alla direttiva #if viene mantenuto nell'unità di conversione.

Grammatica

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

if-part :
testo if-line

if-line :
#if costante-espressione
identificatore #ifdef
identificatore #ifndef

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

elif-line :
#elif costante-espressione

else-part :
testo else-line

else-line :
#else

endif-line :
#endif

Osservazioni:

Ogni direttiva #if in un file di origine deve corrispondere a una direttiva di chiusura #endif . È possibile visualizzare un numero qualsiasi di direttive #elif tra le direttive #if e #endif, ma è consentita al massimo una direttiva #else. La direttiva #else , se presente, deve essere l'ultima direttiva prima di #endif.

Le direttive #if, #elif, #else e #endif possono annidare nelle parti di testo di altre direttive #if . Ogni direttiva #else annidata, #elif o #endif appartiene alla direttiva #if precedente più vicina.

Tutte le direttive di compilazione condizionale, ad esempio #if e #ifdef, devono corrispondere a una direttiva di chiusura #endif prima della fine del file. In caso contrario, viene generato un messaggio di errore. Quando le direttive di compilazione condizionale sono contenute in file di inclusione, devono soddisfare le stesse condizioni: non devono esistere direttive di compilazione condizionale non corrispondenti alla fine del file di inclusione.

La sostituzione delle macro viene eseguita all'interno della parte della riga che segue un comando #elif, pertanto è possibile usare una chiamata di macro nell'espressione costante.

Il preprocessore seleziona una delle occorrenze di testo indicate per un'ulteriore elaborazione. Un blocco specificato nel testo può essere qualsiasi sequenza di testo. Può occupare più righe. In genere il testo è il testo del programma che ha un significato per il compilatore o il preprocessore.

Il preprocessore elabora il testo selezionato e lo passa al compilatore. Se il testo contiene direttive del preprocessore, il preprocessore esegue tali direttive. Solo i blocchi di testo selezionati dal preprocessore vengono compilati.

Il preprocessore seleziona un singolo elemento di testo valutando l'espressione costante dopo ogni #if o #elif direttiva finché non trova un'espressione costante true (diverso da zero). Seleziona tutto il testo (incluse altre direttive del preprocessore che iniziano con #) fino al #elif associato, #else o #endif.

Se tutte le occorrenze di constant-expression sono false o se non vengono visualizzate direttive #elif, il preprocessore seleziona il blocco di testo dopo la clausola #else. Se non è presente alcuna clausola #else e tutte le istanze di constant-expression nel blocco #if sono false, non viene selezionato alcun blocco di testo.

L'espressione costante è un'espressione costante integer con queste restrizioni aggiuntive:

  • Le espressioni devono avere un tipo integrale e possono includere solo costanti integer, costanti carattere e l'operatore definito .

  • L'espressione non può usare sizeof o un operatore type-cast.

  • L'ambiente di destinazione potrebbe non essere in grado di rappresentare tutti gli intervalli di interi.

  • La traduzione rappresenta il tipo allo stesso modo del tipo int longe unsigned int allo stesso modo di unsigned long.

  • Il convertitore può traslare le costanti carattere in un set di valori di codice diverso dal set per l'ambiente di destinazione. Per determinare le proprietà dell'ambiente di destinazione, usare un'app compilata per tale ambiente per controllare i valori dei LIMITI. Macro H .

  • L'espressione non deve eseguire query sull'ambiente e deve rimanere isolata dai dettagli di implementazione nel computer di destinazione.

Operatori del preprocessore

defined

L'operatore di preprocessore definito può essere usato in espressioni costanti speciali, come illustrato nella sintassi seguente:

defined( identifier )
identificatore definito

Questa espressione costante viene considerata true (diverso da zero) se l'identificatore è attualmente definito. In caso contrario, la condizione è false (0). Un identificatore definito come testo vuoto viene considerato definito. L'operatore definito può essere usato in un #if e in una direttiva #elif , ma non altrove.

Nell'esempio seguente, le direttive #if e #endif controllano la compilazione di una delle tre chiamate di funzione:

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

La chiamata di funzione a credit viene compilata se è definito l'identificatore CREDIT. Se è definito l'identificatore DEBIT, viene compilata la chiamata di funzione a debit. Se non viene definito alcun identificatore, viene compilata la chiamata a printerror. Sia CREDIT che credit sono identificatori distinti in C e C++ perché i relativi casi sono diversi.

Per le istruzioni di compilazione condizionali nell'esempio seguente si presuppone una costante simbolica precedentemente definita, denominata 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

Il primo blocco di #if mostra due set di direttive #if annidate, #else e #endif. Il primo set delle direttive viene elaborato solo se DLEVEL > 5 è true. In caso contrario, le istruzioni dopo #else vengono elaborate.

Le direttive #elif e #else nel secondo esempio vengono utilizzate per effettuare una delle quattro scelte, in base al valore di DLEVEL. La costante STACK è impostata su 0, 100 o 200, a seconda della definizione di DLEVEL. Se DLEVEL è maggiore di 5, allora l'istruzione

#elif DLEVEL > 5
display(debugptr);

viene compilato e STACK non è definito.

Generalmente la compilazione condizionale viene utilizzata per evitare più inclusioni dello stesso file di intestazione. In C++, dove le classi sono spesso definite nei file di intestazione, i costrutti simili a questo possono essere usati per impedire più definizioni:

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

class Example
{
    //...
};

#endif // !defined( EXAMPLE_H )

Il codice precedente verifica se la costante simbolica EXAMPLE_H è definita. In tal caso, il file è già stato incluso e non richiede la rielaborazione. In caso contrario, la costante EXAMPLE_H viene definita per contrassegnare EXAMPLE.H come già elaborato.

__has_include

Visual Studio 2017 versione 15.3 e successive: determina se un'intestazione della libreria è disponibile per l'inclusione:

#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

Vedi anche

Direttive del preprocessore