views:

161

answers:

4

I occasionally write code something like this:

// file1.cpp
#define DO_THIS 1

#if DO_THIS
    // stuff
#endif

During the code development I may switch the definition of DO_THIS between 0 and 1. Recently I had to rearrange my source code and copy some code from one file to another. But I found that I had made a mistake and the two parts had become separated like so:

// file1.cpp
#define DO_THIS 1

and

// file2.cpp
#if DO_THIS
    // stuff
#endif

Obviously I fixed the error, but then thought to myself, why didn't the compiler warn me? I have the warning level set to 4. Why isn't #if X suspicious when X is not defined?

One more question: is there any systematic way I could find out if I've made the same mistake elsewhere? The project is huge.

EDIT: I can understand having no warning with #ifdef that makes perfect sense. But surely #if is different.

+1  A: 

The compiler didn't generate a warning because this is a preprocessor directive. It's evaluated and resolved before the compiler sees it.

Greg D
This is humerous as a comment - but not really very helpful as an answer! 99.9% of the time, people will say compiler and mean everything from preprocessing to linking....and it's reasonable when you think that a single call to something like 'g++' does it all!
Richard Corden
@Richard: This answer is actually kinda' tongue-in-cheek. I was cracking wise about how often I've seen answers (in the C++ community at large) that are technically correct, yet utterly without value. ;) If I really wanted to take the joke to the nth degree, I would also have included a couple references to the C++ standard.
Greg D
+4  A: 

gcc can generate a warning for this, but its probably not required by the standard:

-Wundef
Warn if an undefined identifier is evaluated in an `#if' directive.

Bill
Glad to see that the GNU people realized it was a potential error.
Mick
It's also a common rule in saftey critical coding standards.
Richard Corden
+7  A: 

Again, as it often happens, the answer to the "why" question is just: it was done that way because some time ago it was decided to do it this way. When you use an undefined macro in an #if it is substituted with 0. You want to know whether it is actually defined - use defined() directive.

There some interesting benefits to that "default to 0" approach though. Especially when you are using macros that might be defined by the platform, not our own macros.

For example, some platforms offer macros __BYTE_ORDER, __LITTLE_ENDIAN and __BIG_ENDIAN to determine their endianness. You could write preprocessor directive like

#if __BYTE_ORDER == __LITTLE_ENDIAN
  /* whatever */
#else
  /* whatever */
#endif

But if you try to compile this code on a platform that does not define these non-standard macros at all (i.e. knows nothing about them), the above code will be translated by preprocessor into

#if 0 == 0
...

and the little-endian version of the code will be compiled "by default". If you wrote the original #if as

#if __BYTE_ORDER == __BIG_ENDIAN
...

then the big-endian version of the code would be compiled "by default".

I can't say that #if was defined as it was specifically for tricks like the above, but it comes useful at times.

AndreyT
"use defined() directive"... defined()? I could not find that on msdn.
Mick
I'm talking about `#if defined(<macro>)`. In MSDN it should be under `#if`. Maybe it is properly called "operator" , not "directive".
AndreyT
do you mean #ifdef ?
Bill
@Bill: I mean specifically operator `defined(...)`. `#if defined(...)` has an equivalent shorter form `#ifdef`, but if you need a more complex constrolling expression with logical operators, then `defined(...)` is the way to go.
AndreyT
+1  A: 

If I'm thinking about this correctly.

Preprocessor directives are handled before any source code is compiled. During that phase(s) of translation in which this occurs all preprocessor directives, macros, etc are handled and then the actual source code is compiled.

Since #if is used to determine if X has been defined and carry out some action if it has or has not been defined. The #if in the code snippet would compile without any errors because there aren't any errors as far as the compiler is concerned. You could always create a header file with specific #defines that your application would need and then include that header.

ChadNC