Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you switch() on an enum that has multiple similar values in C/C++?

Tags:

c

enums

Let's say that I have an enum as such:

typedef enum
{
    gray = 4, //Gr[ae]y should be the same
    grey = 4,
    blue = 5,
    red  = 6
} FOO;

I then want to switch on this:

switch(f){
    case gray:
    case grey:
        printf("The color of an elephant\n"); break;
    case blue:
        printf("The color of the sky\n"); break;
    case red:
        printf("The color of an apple\n"); break;
    default:
        printf("I don't know this color\n"); 
 }

Basically I have enum that has values that are essentially synonyms that I want to handle exactly the same way. I tried the above switch, but it doesn't compile for me. Is there a way to do this, or am I stuck using if/else logic? (I'd rather not as there are 20+ enums and the switch is much cleaner looking

EDIT: Yes, I know that I can just pick one or the other (and no locales are not the solution), but doesn't it seem kind of odd that enums explicitly allow you to declare duplicate values yet you then can't use them in a switch statement? I want to use enums so that I can statically enforce in a library API that they are sending proper values (yes I know you can get around with typecasting, I'm just trying to prevent stupid mistakes and such). If I do so it now seems like I lose the ability to use it in a switch statement.

The compiler is just reducing the logic down to if/else logic. If case 4: case 5: bar(); break;

is legal, why can't case 4: case 4: bar(); break;

be legal? The compiler should be able to optimize that to one statement and move on.

like image 775
FuriousGeorge Avatar asked Mar 15 '23 15:03

FuriousGeorge


1 Answers

You can't.

The C standard requires all the constant expression in the case labels for a given switch statement to have distinct values. This is checked at compile time. Having two case labels with the same value is a constraint violation, requiring a compile-time diagnostic. (This could be a non-fatal warning, but I don't know of any compiler that doesn't treat it as a fatal error.)

The rule is stated in N1570 6.8.4.2p3:

The expression of each case label shall be an integer constant expression and no two of the case constant expressions in the same switch statement shall have the same value after conversion.

C++ has similar rules.

This means, for example that this:

switch (blah) {
    case 2+2:
    case 4:
        /* ... */
}

is also illegal. The compiler checks the values of the expressions, regardless of whether they have some distinct meaning to a human reader.

You'll just have to pick either gray or grey.

(In principle, the standard could have permitted two case labels to have the same value as long as they're grouped together, as in your example. But it wasn't defined that way, probably because it wasn't considered useful enough.)

like image 150
Keith Thompson Avatar answered Mar 17 '23 05:03

Keith Thompson