Comparación de macros de directiva if

25

¿Por qué se #ifcumple la condición en el siguiente código?

#include <iostream>
#define VALUE foo    

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

Respuestas:

26

La página en cppreference.com dice:

Después de toda expansión y evaluación macro de expresiones definidas y __has_include (desde C ++ 17), cualquier identificador que no sea un literal booleano se reemplaza con el número 0 (esto incluye identificadores que son palabras clave léxicamente, pero no tokens alternativos como y )

Entonces ambos fooy barson reemplazados por 0.

BessieTheCow
fuente
¿Qué pasa con C ++ 98, C ++ 03, C ++ 11 y C ++ 14?
kelalaka
1
@kelalaka Es todo lo mismo. Ha sido así desde C89.
SS Anne
1
@kelalaka El "desde C ++ 17" solo se refiere a la parte "y __has_include". Antes de C ++ 17 era lo mismo, solo con esa parte omitida.
BessieTheCow
15

En una #ifdeclaración, cualquier identificador que permanezca después de la sustitución de macro (excepto para truey false) se reemplaza con la constante 0. Entonces su directiva se convierte

#if 0 == 0

cual es verdad.

1201 Programa Alarma
fuente
Para aclarar, '#define VALUE foo' define el símbolo 'VALUE' para resolver al mismo valor que el símbolo 'foo', pero el símbolo 'foo' no tiene significado, por lo que se interpretará como 0.
ManicDee
14

Esto se debe a que fooni barse les ha dado ninguna definición o valor, por lo que son iguales (es decir, reemplazados por un valor "0"). Los compiladores darán advertencias sobre esto.

El MSVCcompilador (Visual Studio 2019) ofrece lo siguiente:

advertencia C4668: 'foo' no se define como una macro de preprocesador, reemplazando con '0' para '# if / # elif'
advertencia C4668: 'bar' no se define como una macro de preprocesador, reemplazando con '0' para '#if / # elif '

Por VALUElo tanto, se le da el valor '0' (predeterminado para foo) y bartambién tiene '0', por lo que se VALUE == barevalúa como "VERDADERO".

Del mismo modo, clang-clda lo siguiente:

advertencia: 'foo' no está definido, se evalúa a 0 [-Wundef]
advertencia: 'barra' no está definido, se evalúa a 0 [-Wundef]

Adrian Mole
fuente
¿La advertencia es obligatoria o es una característica de los compiladores?
kelalaka
1
@kelalaka Hasta donde sé, ¡no son obligatorias las "advertencias" del compilador! Incluso con los compiladores MSVCy clang-cl, esta advertencia se puede deshabilitar (ya sea específicamente o estableciendo un 'nivel' de advertencia apropiado).
Adrian Mole
0

Para lograr lo que busca, intente esto:

#include <iostream>
#define DEBUG  

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

En este caso, puede desactivar las declaraciones de depuración cambiando "define" a "undef".

#include <iostream>
#undef DEBUG  

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

Es posible que su compilador le permita definir DEPURACIÓN fuera del código, en cuyo punto puede reducir el código a

#include <iostream>

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

Y luego invoque el compilador con una opción como -DDEBUG = 0

Consulte el capítulo sobre Programación defensiva en Steve McConnell, "Código completo".

ManicDee
fuente