80

My preprocessor appears to assume that undefined constants are 0 for the purpose of evaluating #if conditions.

Can this be relied upon, or do undefined constants give undefined behaviour?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Tony Park
  • 1,247
  • 1
  • 9
  • 14

3 Answers3

87

Yes, it can be relied upon. The C99 standard specifies at §6.10.1 ¶3:

After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers are replaced with the pp-number 0

Edit

Sorry, I thought it was a C question; still, no big deal, the equivalent section in the C++ standard (§16.1 ¶4) states:

After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers and keywords, except for true and false, are replaced with the pp-number 0

The only difference is the different handling of true and false, which in C do not need special handling, while in C++ they have a special meaning even in the preprocessing phase.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 2
    Just Curious: Any reason why compiler does this? Why can't compiler throw error message when expression is undefined and compiler anyway come to know this? Does this not lead to unnecessary bugs in the software. I am really confused why newer compilers do not take care of this. Is it only because backward compatibility has to be maintained or something? – Rajesh May 09 '18 at 13:45
  • 1
    That's what the specification says, which probably formalized existing behavior (the C preprocessor goes back to the 70s); even modern compilers cannot decide to do differently if they want to implement the C language correctly, and changing the spec now would probably break tons of code. – Matteo Italia May 09 '18 at 14:38
  • Hi there, though this request is rather old, it is still quite interesting. I saw the following code: `#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L` `// code is compatible to C11 standard` `#endif` Does this make sense? This expression lets assume that there have been compilers which behave differently. (Otherwise I could simplify the condition to a simple comparison.) Is there any C or C++ standard where this was unspecified? – MiCo Sep 09 '22 at 10:22
  • @Rajesh You can use `-Wundef` with gcc to pick out underfined macros. Related: https://stackoverflow.com/questions/54476352/how-to-catch-undefined-macro-in-preprocessor-if-condition – Daniel Chin Aug 07 '23 at 12:06
16

An identifier that is not defined as a macro is converted to 0 before the expression is evaluated.

The exception is the identifier true, which is converted to 1. This is specific to the C++ preprocessor; in C, this doesn't happen and you would need to include <stdbool.h> to use true this way, in which case it will be defined as a macro and no special handling is required.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • In C++ `true` is a keyword not a macro - its interpretation has nothing to do with the pre-processor, so it is not an exception. – Clifford Mar 17 '19 at 16:40
  • @Clifford, if you use `true` in a preprocessor directive such as `#if whatever == true`, both `whatever` and `true` are plain identifiers. The preprocessor has its own language, so it needs special casing. – Quirin F. Schroll Jan 24 '22 at 11:09
2

The OP was asking specifically about the C preprocessor and the first answer was correctly referring to the C preprocessor specification. But some of the other comments seem to blur the distinction between the C preprocessor and the C compiler. Just to be clear, those are two different things with separate rules and they are applied in two separate passes.

#if 0 == NAME_UNDEFINED
int foo = NAME_UNDEFINED;
#endif

This example will successfully output the foo definition because the C preprocessor evaluates NAME_UNDEFINED to 0 as part of a conditional expression, but a compiler error is generated because the initializer is not evaluated as a conditional expression and then the C compiler evaluates it as an undefined symbol.

jsheaney
  • 99
  • 1
  • 3