Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the C preprocessor consider enum values as equal?

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

#include <iostream>

enum T { A = 1, B = 2 };
// #define A 1
// #define B 2

int main() {
#if (A == B)
    std::cout << A << B;
#endif
}

If I use #define instead (as commented out), I get no output as I expect.

Reason for the question:

I want to have a mode selector for some test code in which I can easily change modes by commenting/uncommenting lines on top:

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

I know I can use numeric values e.g.

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

but it makes the code less readable.

Is there an elegant solution for this?

like image 383
Gnubie Avatar asked Jan 08 '16 12:01

Gnubie


People also ask

Why is enum used in C?

Enumeration or Enum in C is a special kind of data type defined by the user. It consists of constant integrals or integers that are given names by a user. The use of enum in C to name the integer values makes the entire program easy to learn, understand, and maintain by the same or even different programmer.

Can enum values be changed in C?

You can change default values of enum elements during declaration (if necessary).

Can enum have same value?

Two enum names can have same value. For example, in the following C program both 'Failed' and 'Freezed' have same value 0.

What is the difference between enum and #define in C?

One of the differences between the two is that #define is a pre-processor directive while enum is part of the actual C language. #define statements are processed by the compiler before the first line of C code is even looked at!


3 Answers

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).

like image 107
Simple Avatar answered Oct 07 '22 01:10

Simple


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.

like image 46
Samidamaru Avatar answered Oct 07 '22 03:10

Samidamaru


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.

like image 25
eerorika Avatar answered Oct 07 '22 02:10

eerorika