Порівняння макро-директив


25

Чому виконується #ifумова в наступному коді:

#include <iostream>
#define VALUE foo    

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

Відповіді:


26

На сторінці cppreference.com зазначено:

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

Тож обидва fooі barзамінюються 0.


Що з C ++ 98, C ++ 03, C ++ 11 і C ++ 14?
келалака

1
@kelalaka Це все одно. Так було ще з C89.
СС Енн

1
@kelalaka "З моменту C ++ 17" стосується лише частини "та __has_include". До C ++ 17 це було те саме, лише пропустили цю частину.
BessieTheCow

15

У #ifзаяві будь-який ідентифікатор, який залишається після макрозаміни (крім trueі false), замінюється постійним 0. Так ваша директива стає

#if 0 == 0

що правда.


Щоб уточнити, "#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]
попередження: 'bar' не визначено, оцінюється до 0 [-Wundef]


Чи попередження є обов'язковим або це особливість компіляторів?
келалака

1
@kelalaka Наскільки мені відомо, "попередження" компілятора не є обов'язковими! Навіть із компіляторами MSVCта та clang-clце попередження можна відключити (конкретно, або встановивши відповідний "рівень" попередження).
Адріан Моль

0

Щоб виконати те, що ви хочете, спробуйте:

#include <iostream>
#define DEBUG  

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

У цьому випадку ви можете вимкнути оператори налагодження, змінивши "визначити" на "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

Ознайомтеся з розділом «Оборонне програмування» у Стіві МакКоннел «Код завершений».

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.