为什么两个不同的枚举枚举常量具有相同的整数值?

时间:2012-07-10 11:37:38

标签: c enums

我知道如果我这样定义一个枚举工作日:

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

然后,MON默认情况下内部等于0,TUE为1,WED为2 ......

但如果我这样定义:

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

然后MONTUE都会得到值0。

系统如何在内部区分MON和TUE?我的意思是,如果我宣布这样的事情:

enum weekday today = 0;

那么今天是MON还是TUE?或者,哲学上讲,两者都是?

5 个答案:

答案 0 :(得分:65)

C枚举是“真正的”整数 - 不仅仅因为它们碰巧以这种方式实现,而且因为标准定义了枚举类型以具有整数值。因此today的值是“真的”0.所有发生的事情是你为值0创建了两个不同的名称。

我想那时“今天是MON或TUE”的答案是“是”; - )

语言不会阻止你,因为有时候枚举对同一个值有多个名称是有用的。例如:

enum compression_method {
    COMP_NONE = 0,
    COMP_LOW = 1,
    COMP_HIGH = 2,
    COMP_BEST = 2,
    COMP_FASTEST = 0,
};

答案 1 :(得分:19)

为什么两个不同的枚举常量具有相同的整数值?

因为N1265 C99 standard draft在6.7.2.2/3“枚举说明符”中明确允许它:

  

使用带有=的枚举器可能会产生枚举常量,其值与同一枚举中的其他值重复。

系统如何在内部区分MON和TUE?

我认为这是不可能的,因为它们是编译时常量(6.6 / 6“常量表达式”)。结果他们:

  • 无法修改,以便在编译后使它们不同

  • 没有地址告诉他们:Memory location of enum value in C

    编译时间常量不需要任何地址,因为地址对于您无法修改的内容无用。

GCC只是在编译时用汇编中的立即值替换枚举成员的使用。考虑:

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

使用GCC 4.8 x86_64进行编译和反编译:

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

输出包含:

    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

所以我们看到了:

  • enum成员被用作immediates $0x1234,因此无法知道他们来自哪里
  • 变量i来自内存0x0(%rip)(要重新定位),因此可以通过地址区分两个变量

答案 2 :(得分:10)

为了补充其他答案,我将为您提供一个实际示例,说明如何对给定enum上的不同枚举使用相同的值非常有用:

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

然后你可以在你的代码中执行:

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

答案 3 :(得分:8)

它是哲学的(或不是)

#define ZILCH 0
#define NADA  0

有许多用途可以让不同的名称产生相同的数字。

答案 4 :(得分:2)

枚举常量的名称用于分配值,而不是实际值本身。如果将值0指定给今天,则输出值将为0。 是的,MON和TUE都将具有值0,剩余的将被赋值为WED = 1 THU = 2,依此类推。