为什么C预处理器将枚举值视为相等?

为什么即使AB不同,为什么下面的代码中的std::cout行仍然运行?

 #include <iostream> enum T { A = 1, B = 2 }; // #define A 1 // #define B 2 int main() { #if (A == B) std::cout << A << B; #endif } 

如果我使用#define (如注释掉),我没有得到任何输出。

问题的理由:

我想有一个testing代码的模式select器,我可以轻松地通过注释/取消注释上面的行来改变模式:

 enum T { MODE_RGB = 1, MODE_GREY = 2, MODE_CMYK = 3 }; // #define MODE MODE_RGB #define MODE MODE_GREY // #define MODE MODE_CMYK int main() { #if (MODE == MODE_RGB) // do RGB stuff #elif (MODE == MODE_GREY) // do greyscale stuff #else // do CMYK stuff #endif // some common code some_function(arg1, arg2, #if (MODE == MODE_RGB) // RGB calculation for arg3, #elif (MODE == MODE_GREY) // greyscale calculation for arg3, #else // CMYK calculation for arg3, #endif arg4, arg5); } 

我知道我可以使用数值例如

 #define MODE 1 // RGB ... #if (MODE == 1) // RGB 

但是会使代码不易读。

有没有一个优雅的解决scheme呢?

没有叫做ABmacros,所以在你的#if行中, AB被replace为0 ,所以你实际上有:

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

预编译器在编译器知道你的enum之前运行。 预处理器只知道macros( #define )。

这是因为预处理器在编译之前工作。

由于枚举定义是在编译时发生的,所以在预处理时,A和B都将被定义为空(pp-number 0 ) – 因此是相等的,因此输出语句被包含在编译后的代码中。

当你使用#define它们在预处理时被定义为不同的,因此语句的计算结果为false。

关于你想要做什么的评论,你不需要使用预处理器#if来做到这一点。 if MODEMODE_GREY (或者MODE_RGB或者MODE_CMYK )都是定义的, if你可以使用这个标准:

 #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; } 

另一种只使用预处理器的方法是正确地回答 @TripeHound。

未定义macros的标识符在条件预处理器指令中被解释为值0。 因此,由于您没有定义macrosAB ,所以它们都被认为是0,并且两个0彼此相等。

未定义(对于预处理器)标识符被视为0的原因是因为它允许在条件中使用未定义的macros而不使用#ifdef

预处理器在编译器之前运行,这意味着预处理器不知道编译器定义的符号的任何内容,因此它不能根据它们而行动。

正如其他答案所说,C预处理器不会看到枚举。 它期望并且只能理解macros。

根据C99标准 ,§6.10.1(有条件包含):

在由于macros扩展和所定义的一元运算符的所有replace之后,所有剩余的标识符被replace为pp-number0

换句话说,在#if或#elif指令中,任何不能被扩展的macros,因为它们不存在/是未定义的,它们的行为就像被定义为0一样,因此总是等于彼此。

你可以在GCC / clang中使用警告选项-Wundef捕获像这样的非预期行为(你可能想用-Werror = undef使它变成致命的)。

其他答案解释了为什么你正在尝试不工作; 另外,我可能会去:

 #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 

如果存在与“真实”源代码冲突的危险,则可能需要RGB / GREY / CMYK上的前缀。

这些post解释了为什么,但是为了保持可读性,一个可能的解决scheme可能就是这样

 #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 } 

您只需要在顶部更改macros,即只定义您感兴趣的macros。 你也可以包括一个检查,以确保只有一个被定义,如果没有,然后做#error "You must define MODE_RGB, MODE_GREY or MODE_CMYK