Search code examples
iosccompilationmacrosapple-clang

What is the result of #if MACRO and MACRO is defined without value?


If I defined a macro:

#define FOO

And in the code I check it like:

#if FOO
//1
#else
//2
#endif

Which branch will it go? Will the result be different by different compilers? What is the FOO value in the #if FOO?


Solution

  • C17 6.10.1 specifies the syntax for #if as:

    # if constant-expression new-line groupopt

    Where:

    • A constant expression is an item for example like 1 (integer constant) or 1+1 (integer constant expression), or a preprocessor token expanding to such.
    • New line is the end of the #if line.
    • Group (optional) is whatever you put between #if and #endif etc.

    6.10.1 further states that macro expansion inside #if is done as:

    After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers (including those lexically identical to keywords) are replaced with the pp-number 0, and then each preprocessing token is converted into a token. The resulting tokens compose the controlling constant expression which is evaluated according to the rules of 6.6.

    Meaning that if some token after #if is not a known preprocessor token, it gets replaced with 0. The reference at the end to 6.6 refers to the chapter defining a constant expression.


    Conclusion: if FOO is defined and a known pre-processor token, it will get expanded but the macro is empty in this case. The #if will end up missing a constant expression, since that mandatory part of the syntax is not present before the new line. Meaning we get a syntax error - it is invalid C and will not compile without compiler diagnostics getting raised (see What must a C compiler do when it finds an error?).

    However, if FOO was unknown either because it was misspelled or missing, or simply because it was defined in another translation unit unknown to the current one, it will get replaced with 0 and the #if will evaluate as false.


    Note that defines that are passed to the program using compiler options such as for example gcc -D may have a default value applied to them. For gcc and clang, that value is 1. https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html

    -D name

    Predefine name as a macro, with definition 1.