Comparação de macro da diretiva If

25

Por que a #ifcondição no seguinte código foi atendida:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
michalt38
fonte

Respostas:

26

A página em cppreference.com indica:

Após toda expansão e avaliação de macro de expressões definidas e __has_include (desde C ++ 17), qualquer identificador que não seja um literal booleano é substituído pelo número 0 (isso inclui identificadores que são palavras-chave lexicamente, mas não tokens alternativos como e )

Então, ambos fooe barsão substituídos por 0.

BessieTheCow
fonte
E o C ++ 98, C ++ 03, C ++ 11 e C ++ 14?
kelalaka 21/03
11
@kelalaka É tudo a mesma coisa. Tem sido assim desde C89.
SS Anne
11
@kelalaka O "since C ++ 17" refere-se apenas à parte "and __has_include". Antes do C ++ 17, era o mesmo, apenas com essa parte omitida.
BessieTheCow 21/03
15

Em uma #ifdeclaração, qualquer identificador que permanece após a substituição da macro (exceto truee false) é substituído pela constante 0. Então sua diretiva se torna

#if 0 == 0

que é verdade.

1201ProgramAlarm
fonte
Para esclarecer, '#define VALUE foo' define o símbolo 'VALUE' para resolver o mesmo valor que o símbolo 'foo', mas o símbolo 'foo' não tem significado, portanto será interpretado como 0.
ManicDee
14

Isso ocorre porque nem foonem barter sido dada qualquer definição ou valor - então eles são os mesmos (ou seja substituído por um valor "0"). Os compiladores darão avisos sobre isso.

O MSVCcompilador (Visual Studio 2019) fornece o seguinte:

aviso C4668: 'foo' não está definido como uma macro de pré-processador, substituindo por '0' para '# if / # elif'
aviso C4668: 'bar' não está definido como uma macro de pré-processador, substituindo por '0' para '#if / # elif '

Assim, VALUEé dado o valor '0' (padrão para foo) e bartambém possui '0', então VALUE == baravalia como "TRUE".

Da mesma forma, clang-clfornece o seguinte:

aviso: 'foo' não está definido, avalia como 0 [-Wundef]
aviso: 'bar' não está definido, avalia como 0 [-Wundef]

Adrian Mole
fonte
O aviso é obrigatório ou é um recurso dos compiladores?
kelalaka 21/03
11
@kelalaka Que eu saiba, nenhum 'aviso' do compilador é obrigatório! Mesmo com os compiladores MSVCe clang-cl, esse aviso pode ser desabilitado (especificamente, ou definindo um nível de aviso apropriado).
Adrian Mole
0

Para realizar o que você procura, tente o seguinte:

#include <iostream>
#define DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Nesse caso, você pode desativar as instruções de depuração alterando o "define" para "undef".

#include <iostream>
#undef DEBUG  

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

Você pode achar que seu compilador permite definir DEBUG fora do próprio código; nesse momento, você pode reduzir o código para

#include <iostream>

int main() {    
#ifdef DEBUG
    std::cout << "WORKS!" << std::endl;
#endif
}

E, em seguida, chame o compilador com uma opção como -DDEBUG = 0

Confira o capítulo sobre programação defensiva em Steve McConnell, "Código completo".

ManicDee
fonte