michalt38
michalt38

Reputation: 1193

If-directive macro comparison

Why is the #if condition in the following code fulfilled:

#include <iostream>
#define VALUE foo    

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

Upvotes: 27

Views: 2057

Answers (4)

eesiraed
eesiraed

Reputation: 4654

The page on cppreference.com states:

After all macro expansion and evaluation of defined and __has_include (since C++17) expressions, any identifier which is not a boolean literal is replaced with the number ​0​ (this includes identifiers that are lexically keywords, but not alternative tokens like and).

So VALUE is first replaced with foo, and then both foo and bar are replaced with 0.

Upvotes: 29

ManicDee
ManicDee

Reputation: 732

To accomplish what you are after, try this:

#include <iostream>
#define DEBUG  

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

In this case you can turn the debugging statements off by changing the "define" to "undef".

#include <iostream>
#undef DEBUG  

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

You might find that your compiler allows you to define DEBUG outside the code itself, at which point you can reduce the code to

#include <iostream>

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

And then invoke the compiler with an option such as -DDEBUG=0

Check out the chapter on Defensive Programming in Steve McConnell, "Code Complete."

Upvotes: 1

Adrian Mole
Adrian Mole

Reputation: 51815

This is because neither foo nor bar have been given any definition or value - so they are the same (i.e. replaced with a "0" value). Compilers will give warnings about this.

The MSVC compiler (Visual Studio 2019) gives the following:

warning C4668: 'foo' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
warning C4668: 'bar' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'

So VALUE is given the value '0' (default for foo) and bar also has '0', so VALUE == bar evaluates to "TRUE."

Similarly, clang-cl gives the following:

warning : 'foo' is not defined, evaluates to 0 [-Wundef]
warning : 'bar' is not defined, evaluates to 0 [-Wundef]

Upvotes: 17

1201ProgramAlarm
1201ProgramAlarm

Reputation: 32732

In a #if statement, any identifier that remains after macro substitution (except for true and false) are replaced with the constant 0. So your directive becomes

#if 0 == 0

which is true.

Upvotes: 16

Related Questions