If-директива макроса сравнения

25

Почему выполняется #ifусловие в следующем коде:

#include <iostream>
#define VALUE foo    

int main() {    
#if VALUE == bar
    std::cout << "WORKS!" << std::endl;
#endif // VALUE
}
michalt38
источник

Ответы:

26

Страница на cppreference.com состояниях:

После всех расширений макросов и оценки определенных выражений и выражений __has_include (начиная с C ++ 17) любой идентификатор, который не является логическим литералом, заменяется числом 0 (это включает в себя идентификаторы, которые являются лексическими ключевыми словами, но не альтернативные токены, такие как и ).

Так что оба fooи barзаменены на 0.

BessieTheCow
источник
А как насчет C ++ 98, C ++ 03, C ++ 11 и C ++ 14?
Келалака
1
@kelalaka Это все то же самое. Так было с C89.
SS Anne
1
@kelalaka «С C ++ 17» относится только к части «и __has_include». До C ++ 17 было то же самое, только с этой частью опущено.
BessieTheCow
15

В #ifоператоре любой идентификатор, который остается после подстановки макроса (кроме trueи false), заменяется константой 0. Таким образом, ваша директива становится

#if 0 == 0

что является правдой.

1201ProgramAlarm
источник
Для пояснения, «#define VALUE foo» определяет символ «VALUE» для разрешения того же значения, что и символ «foo», но символ «foo» не имеет значения, поэтому он будет интерпретирован как 0.
ManicDee
14

Это связано с тем, что ни то, fooни другое не barбыло дано ни определения, ни значения - поэтому они одинаковы (т.е. заменены значением «0»). Компиляторы будут предупреждать об этом.

MSVCКомпилятор (Visual Studio 2019) дает следующее:

предупреждение C4668: 'foo' не определен как макрос препроцессора, заменив на '0' для '# if / # elif'
предупреждение C4668: 'bar' не определен как макрос препроцессора, заменив на '0' для '#if / # Элиф»

Так VALUEдается значение «0» (по умолчанию для foo), а barтакже имеет «0», такVALUE == bar оценивается как «ИСТИНА».

Аналогично, clang-clдает следующее:

предупреждение: 'foo' не определено, оценивается в 0 [-Wundef]
предупреждение: 'бар' не определено, оценивается в 0 [-Wundef]

Адриан Моул
источник
Является ли предупреждение обязательным или это особенность компиляторов?
Келалака
1
@kelalaka Насколько мне известно, никакие «предупреждения» компилятора не являются обязательными! Даже с MSVCи clang-clкомпиляторы, это предупреждение может быть отключено (либо специально, либо установив соответствующее предупреждение «уровень»).
Адриан Моль
0

Чтобы выполнить то, что вы хотите, попробуйте это:

#include <iostream>
#define DEBUG  

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

В этом случае вы можете отключить операторы отладки, изменив «define» на «undef».

#include <iostream>
#undef DEBUG  

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

Вы можете обнаружить, что ваш компилятор позволяет вам определять DEBUG вне самого кода, после чего вы можете уменьшить код до

#include <iostream>

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

А затем вызовите компилятор с параметром, например -DDEBUG = 0

Прочтите главу «Защитное программирование» Стива Макконнелла «Код завершен».

ManicDee
источник