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

A diretiva #if , com as diretivas #elif, #elsee #endif , controla a compilação de partes de um arquivo de origem. Se a expressão que você escreve (depois da #if) tiver um valor diferente de zero, o grupo de linhas imediatamente após a diretiva de #if será mantido na unidade de tradução.

Gramática

condicional :
    If-Part elif-Partsissentenceoptdepartelinha

If-Part :
    texto if-line

If-line :
    #ifexpressão de constante
    identificador de #ifdef
    identificador de #ifndef

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

elif-linha :
    #elifexpressão de constante

parte else :
    texto else-line

linha de else :
    #else

endif-linha :
    #endif

Comentários

Cada diretiva de #if em um arquivo de origem deve ser correspondida por uma diretiva de #endif de fechamento. Qualquer número de diretivas de #elif pode aparecer entre as diretivas #if e #endif , mas no máximo uma diretiva #else é permitida. A diretiva #else , se presente, deve ser a última diretiva antes de #endif.

As diretivas #if, #elif, #elsee #endif podem se aninhar nas partes de texto de outras diretivas de #if . Cada diretiva #elseaninhada, #elifou #endif pertence à diretiva #if anterior mais próxima.

Todas as diretivas de compilação condicional, como #if e #ifdef, devem corresponder a uma diretiva de fechamento #endif antes do final do arquivo. Caso contrário, uma mensagem de erro será gerada. Quando as políticas de compilação condicional estão contidas em arquivos de inclusão, elas devem satisfazer às mesmas circunstâncias: não deve haver nenhuma política de compilação condicional sem correspondência no fim do arquivo de inclusão.

A substituição de macro é feita dentro da parte da linha que segue um comando #elif , portanto, uma chamada de macro pode ser usada na expressão Constant.

O pré-processador seleciona uma das ocorrências de texto determinadas para processamento adicional. Um bloco especificado no texto pode ser qualquer sequência de texto. Ele pode ocupar mais de uma linha. Normalmente, o texto é um texto de programa que tem significado para o compilador ou o pré-processador.

O pré-processador processa o texto selecionado e o passa para o compilador. Se o texto contiver diretivas de pré-processador, o pré-processador executará essas diretivas. Somente os blocos de texto selecionados pelo pré-processador são compilados.

O pré-processador seleciona um único item de texto , avaliando a expressão constante seguindo cada #if ou diretiva de #elif até encontrar uma expressão constante verdadeira (diferente de zero). Ele seleciona todo o texto (incluindo as demais diretivas de pré-processador começando com # ) até seu #elifassociado, #elseou #endif.

Se todas as ocorrências de expressão de constante forem false ou se nenhuma #elif diretivas aparecer, o pré-processador selecionará o bloco de texto após a cláusula #else . Quando não há nenhuma cláusula #else e todas as instâncias de expressão constante no bloco de #if são false, nenhum bloco de texto é selecionado.

A expressão de constante é uma expressão de constante inteira com estas restrições adicionais:

  • As expressões devem ter um tipo integral e podem incluir apenas constantes de inteiro, constantes de caractere e o operador definido .

  • A expressão não pode usar sizeof ou um operador de conversão de tipo.

  • O ambiente de destino pode não ser capaz de representar todos os intervalos de inteiros.

  • A tradução representa o tipo int da mesma maneira que o tipo long , e unsigned int da mesma maneira como unsigned long .

  • O tradutor pode traduzir a constante de caracteres como um conjunto de valores de código diferentes do conjunto para o ambiente de destino. Para determinar as propriedades do ambiente de destino, use um aplicativo criado para esse ambiente para verificar os valores dos limites. Macros H.

  • A expressão não deve consultar o ambiente e deve permanecer isolado dos detalhes de implementação no computador de destino.

Operadores do pré-processador

definido

O operador de pré-processador definido pode ser usado em expressões de constantes especiais, conforme mostrado pela seguinte sintaxe:

definido (identificador)
identificadordefinido

Essa expressão constante é considerada true (diferente de zero) se o identificador estiver definido no momento. Caso contrário, a condição será false (0). Um identificador definido como texto vazio é considerado definido. O operador definido pode ser usado em um #if e uma diretiva de #elif , mas em outro lugar.

No exemplo a seguir, as diretivas #if e #endif controlam a compilação de uma das três chamadas de função:

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

A chamada de função para credit será compilada se o identificador CREDIT estiver definido. Se o identificador DEBIT estiver definido, a chamada de função para debit será compilada. Se nenhum identificador for definido, a chamada para printerror será compilada. Ambos CREDIT e credit são identificadores distintos em C e C++ porque seus casos são diferentes.

As instruções de compilação condicional no exemplo a seguir pressupõem uma constante simbólica definida anteriormente denominada 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

O primeiro bloco #if mostra dois conjuntos de diretivas aninhadas #if, #elsee #endif . O primeiro conjunto de políticas será processado somente se DLEVEL > 5 for verdadeiro. Caso contrário, as instruções após #else são processadas.

As diretivas #elif e #else no segundo exemplo são usadas para fazer uma das quatro opções, com base no valor de DLEVEL . A constante STACK é definida como 0, 100 ou 200, dependendo da definição de DLEVEL. Se DLEVEL for maior que 5, a declaração

#elif DLEVEL > 5
display(debugptr);

é compilado e STACK não é definido.

A compilação condicional é usada normalmente para evitar várias inclusões do mesmo arquivo de cabeçalho. Em C++, em que as classes geralmente são definidas em arquivos de cabeçalho, construções como esta podem ser usadas para impedir várias definições:

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

class Example
{
    //...
};

#endif // !defined( EXAMPLE_H )

O código acima verifica se a constante EXAMPLE_H foi definida. Nesse caso, o arquivo já foi incluído e não precisa ser reprocessado. Caso contrário, a constante EXAMPLE_H será definida para marcar EXAMPLE.H como já processado.

__has_include

Visual Studio 2017 versão 15,3 e posterior: determina se um cabeçalho de biblioteca está disponível para inclusão:

#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

Confira também

Diretivas do pré-processador