Why does the C preprocessor consider enum values as equal?

后端 未结 7 1256
南方客
南方客 2020-12-08 12:48

Why does the std::cout line in the following code run even though A and B are different?

#include 

en         


        
相关标签:
7条回答
  • 2020-12-08 13:25

    The preprocessor runs before the compiler, which means that the preprocessor doesn't know anything about symbols defined by the compiler and therefore it can't act depending on them.

    0 讨论(0)
  • 2020-12-08 13:26

    There are no macros called A or B, so on your #if line, A and B get replaced by 0, so you actually have:

    enum T { A = 1, B = 2 };
    
    int main() {
    #if (0 == 0)
        std::cout << A << B;
    #endif
    }
    

    The preprocessor runs before the compiler knows anything about your enum. The preprocessor only knows about macros (#define).

    0 讨论(0)
  • 2020-12-08 13:27

    This is because the preprocessor works before compile time.

    As the enum definitions occur at compile time, A and B will both be defined as empty (pp-number 0) - and thus equal - at pre-processing time, and thus the output statement is included in the compiled code.

    When you use #define they are defined differently at pre-processing time and thus the statement evaluates to false.

    In relation to your comment about what you want to do, you don't need to use pre-processor #if to do this. You can just use the standard if as both MODE and MODE_GREY (or MODE_RGB or MODE_CMYK) are all still defined:

    #include <iostream>
    
    enum T { MODE_RGB = 1, MODE_GREY = 2, MODE_CMYK = 3 };
    
    #define MODE MODE_GREY
    
    int main()
    {
        if( MODE == MODE_GREY )
            std::cout << "Grey mode" << std::endl;
        else if( MODE == MODE_RGB )
            std::cout << "RGB mode" << std::endl;
        else if( MODE == MODE_CMYK )
            std::cout << "CMYK mode" << std::endl;
    
        return 0;
    }
    

    The other option using only the pre-processor is to do this as @TripeHound correctly answered below.

    0 讨论(0)
  • 2020-12-08 13:40

    Identifiers that are not defined macros are interpreted as value 0 in conditional preprocessor directives. Therefore, since you hadn't defined macros A and B, they are both considered 0 and two 0 are equal to each other.

    The reason why undefined (to the pre-processor) identifiers are considered 0 is because it allows using undefined macros in the conditional without using #ifdef.

    0 讨论(0)
  • 2020-12-08 13:40

    Other answers explain why what you're trying doesn't work; for an alternative, I'd probably go with:

    #define RGB 1
    #define GREY 2
    #define CMYK 3
    #define MODE RGB
    
    #if MODE == RGB
        //RGB-mode code
    #elif MODE == GREY
        //Greyscale code
    #elif MODE == CMYK
        //CMYK code
    #else
    #    error Undefined MODE
    #endif
    

    You might want prefixes on the RGB/GREY/CMYK if there's a danger of clashes with "real" source code.

    0 讨论(0)
  • 2020-12-08 13:43

    The posts have explained why, but a possible solution for you that keeps readability might be like this

    #define MODE_RGB
    
    int main()
    {        
        #ifdef MODE_RGB
            std::cout << "RGB mode" << std::endl;
        #elif defined MODE_GREY
            std::cout << "Grey mode" << std::endl;
        #elif defined MODE_CMYK
            std::cout << "CMYK mode" << std::endl;
        #endif
    }
    

    You just then need to change the macro at the top, to only the macro you are interested in is defined. You could also include a check to make sure that one and only one is defined and if not then and do #error "You must define MODE_RGB, MODE_GREY or MODE_CMYK

    0 讨论(0)
提交回复
热议问题