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


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.