Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

enums

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?

like image 444
Xu Hong Avatar asked Jul 10 '12 11:07

Xu Hong


People also ask

Can two different enums have the same value?

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

Can we have enum containing enum with same constant?

The values assigned to the enum names must be integral constant, i.e., it should not be of other types such string, float, etc. All the enum names must be unique in their scope, i.e., if we define two enum having same scope, then these two enums should have different enum names otherwise compiler will throw an error.

Are enumeration values coerced to integer?

The enumeration values are coerced to int when they are put in integer context. E.g. myColor++ would assign green to myColor. In Java, all enumeration types are implicitly subclasses of the predefined class Enum. They can have instance data fields, constructors and methods.

Can enum values repeat?

Yes. Use GetValues() method in System. Enum class.


2 Answers

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, }; 
like image 189
Steve Jessop Avatar answered Sep 28 '22 03:09

Steve Jessop


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