65

I know that if I defined an enum weekday like this:

enum weekday {
    MON,
    TUE,
    WED,
    THU,
    FRI,
};

Then, MON would internally equal to 0, by default, and TUE to 1, WED to 2...

But if I define it this way:

enum weekday {
    MON,
    TUE = 0,
    WED,
    THU,
    FRI,
};

Then both MON and TUE would get the value of 0.

How would a system differentiate MON and TUE internally? I mean, if I declare something like this:

enum weekday today = 0;

Then is today MON or TUE? Or, philosophically speaking, both?

5
  • 6
    @quasiverse - I did, MON and TUE are both 0. +1, I didn't know that. Commented Jul 10, 2012 at 11:44
  • 3
    The enum constants are ints. They're just hopefully meaningful names for some integer constants. So what's the deal if you can refer to the same thing with two names? Commented Jul 10, 2012 at 11:47
  • 1
    There's no philosophy, just logic: today == MON == TUE == 0. Commented Jul 10, 2012 at 11:54
  • A "is it legal" version: stackoverflow.com/questions/5561142/duplicate-enum-values-in-c/… Commented Jun 18, 2015 at 13:21
  • it's basically an alternative to constexpr for systems that don't support constexpr. except the constexpr ints are coupled Commented Nov 12, 2017 at 22:19

5 Answers 5

95

C enums are "really" integers -- not just because they happen to be implemented that way, but because the standard defines enum types to have integer values. So the value of today is "really" 0. All that has happened is that you've created two different names for the value 0.

I suppose then that the answer to "is today MON or TUE" is "yes" ;-)

The language doesn't stop you because occasionally it's useful for an enum to have multiple names for the same value. For example:

enum compression_method {
    COMP_NONE = 0,
    COMP_LOW = 1,
    COMP_HIGH = 2,
    COMP_BEST = 2,
    COMP_FASTEST = 0,
};
Sign up to request clarification or add additional context in comments.

5 Comments

Hahahahha, +1 for I suppose then that the answer to "is today MON or TUE" is "yes" ;-) :D
A better solution here is to have COMP_FASTEST = COMP_NONE, in my opinion.
even if MON and TUE were different, the answer to "is today MON or TUE" can still be "yes", given the computer "OR" operation. I think you were searching for "is today MON and TUE"
I accidentally came to this C++ version of this issue meaning to look for Go. If it's not a nonsense question, what I was wondering is if you were to code the cast: compression_method(0) (which at least would make sense in Go, which can use Type aliases for enum integers, if not C++), what would the result be? I assume the answer is "moot", because COMP_NONE and COMP_FASTEST are both really just 0.
@RomnieEE: realistically I think in any language that treats enums in this way, the result of compression_method(0) would be "the value of the type compression_method that is equal to 0". COMP_NONE and COMP_FASTEST are two different names for that value. It's a bit like, if you define static const int FOO = 0; static const int BAR = 0, and then cast 0 to int, what would the result be? It's 0. What you call 0 is up to you ;-)
26

Why can two different enumeration-constants have the same integer value?

Because it is explicitly allowed by the N1265 C99 standard draft at 6.7.2.2/3 "Enumeration specifiers":

The use of enumerators with = may produce enumeration constants with values that duplicate other values in the same enumeration.

How would a system differentiate MON and TUE internally?

I think it is impossible because they are compile time constants (6.6/6 "Constant expressions"). As a consequence they:

  • cannot be modified to make them differ after compilation

  • have no address to tell them apart: Memory location of enum value in C

    Compile time constants don't need any address because addresses are useless for things which you cannot modify.

GCC simply replaces the usage of enum members with immediate values in assembly at compile time. Consider:

#include <stdio.h>

enum E {
    E0 = 0x1234,
    E1 = 0x1234
};
int i = 0x5678;

int main() {
    printf("%d\n", E0);
    printf("%d\n", E1);
    printf("%d\n", i);
    return 0;
}

Compile and decompile with GCC 4.8 x86_64:

gcc -c -g -O0 -std=c89 main.c
objdump -Sr main.o

The output contains:

    printf("%d\n", E0);
   4:       be 34 12 00 00          mov    $0x1234,%esi
  ...
    printf("%d\n", E1);
  18:       be 34 12 00 00          mov    $0x1234,%esi
  ...
    printf("%d\n", i);
  2c:       8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 32 <main+0x32>
                    2e: R_X86_64_PC32       i-0x4
  32:       89 c6                   mov    %eax,%esi

So we see that:

  • the enum members are used as immediates $0x1234, so it is impossible to know where they came from
  • the variable i however comes from memory 0x0(%rip) (to be relocated), so two variables could be differentiated by address

Comments

14

Just to complement on other answers, I'll give you a practical example of how using the same value for different enumerations on a given enum is widely useful:

enum slots_t {
    SLOT_FIRST = 0,
    SLOT_LEFTARM = SLOT_FIRST,
    SLOT_RIGHTARM = 1,
    SLOT_TORSO = 2,
    SLOT_LEFTLEG = 3,
    SLOT_RIGHTLEG = 4,
    SLOT_LAST = SLOT_RIGHTLEG
};

Then you can do in your code:

for (int i = SLOT_FIRST; i <= SLOT_LAST; ++i) { }

2 Comments

I would rather define a SLOT_MAX = 4 instead of SLOTLAST = SLOT_RIGHTLEG in case some other programmer comes to the great idea to exchange the values for SLOT_LEFTLEG and SLOT_RIGHTLEG
Normally I use SLOT_MAX with not forced value to have the compiler assign last + 1. This allow to have array defined, ex: bool slot_valid[SLOT_MAX]; Or looping with more traditional i < SLOT_MAX.
11

It's as philosophical (or not) as

#define ZILCH 0
#define NADA  0

There are many uses where it makes sense to have different names result in the same number.

Comments

2

The name of the enumeration constant is used to assign the value and not the actual value itself. If you assign the value 0 to today the output value will be 0. And yes, both MON and TUE will have the value 0 and the remaining will assigned the value as WED=1 THU=2 and so on.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.