Search code examples
c++c-preprocessorlanguage-lawyerconditional-compilation

#ifdef with multiple tokens, is this legal?


Today I came across some C++ code that contains an #ifdef clause like this:

#ifdef DISABLE_UNTIL OTHER_CODE_IS_READY
   foo();
#endif

Note the space between "DISABLE_UNTIL" and "OTHER_CODE_IS_READY". Essentially there are two tokens specified in the #ifdef line.

My question is, is this legal C++ code? (g++ compiles it without any errors, and it apparently just ignores the second token). And if it is legal, should the second token have any effect?


Solution

  • [C++11 16.1], [C++11 16.5] and, incidentally, [C99 6.10.1/4] all say that this is invalid.

    if-group:
    # if constant-expression new-line groupopt
    # ifdef identifier new-line groupopt
    # ifndef identifier new-line groupopt

    Only one identifier is legal.

    GCC's own documentation agrees.

    My own tests suggest that only the first identifer is accepted, and the second is simply discarded; this may be to ease the implementation, but the standard does require a diagnostic here, so you should see this when you use the -pedantic flag at least.

    #include <iostream>
    using namespace std;
    
    #define A
    #define B
    
    int main() {
        #ifdef A
        std::cout << "a ";
        #endif
    
        #ifdef B
        std::cout << "b ";
        #endif
    
        #ifdef C
        std::cout << "c ";
        #endif
    
        #ifdef B C
        std::cout << "bc ";
        #endif
    
        #ifdef C B
        std::cout << "cb ";
        #endif
    
        return 0;
    }
    
    // Output: "a b bc"
    // Note: "cb" *not* output
    

    Coliru's installation of GCC emits it with or without -pedantic.