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

Xu *_*ong 45 c enums

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

enum weekday {
    MON,
    TUE,
    WED,
    THU,
    FRI,
};
Run Code Online (Sandbox Code Playgroud)

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

但如果我这样定义它:

enum weekday {
    MON,
    TUE = 0,
    WED,
    THU,
    FRI,
};
Run Code Online (Sandbox Code Playgroud)

然后这两个MONTUE将得到的0值.

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

enum weekday today = 0;
Run Code Online (Sandbox Code Playgroud)

那么今天MON还是TUE?或者,从哲学上讲,两者兼而有之?

Ste*_*sop 67

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

我想那时"今天是MON还是TUE"的答案是"是";-)

该语言不会阻止您,因为有时枚举对于相同的值具有多个名称是有用的.例如:

enum compression_method {
    COMP_NONE = 0,
    COMP_LOW = 1,
    COMP_HIGH = 2,
    COMP_BEST = 2,
    COMP_FASTEST = 0,
};
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,更好的解决方案是拥有`COMP_FASTEST = COMP_NONE`. (31认同)
  • 哈哈哈哈,+1为`我想,"今天MON或TUE"的回答是"是";-)`:D (13认同)
  • 即使周一和周二不同,考虑到计算机的“OR”运算,“今天是周一还是周二”的答案仍然可以是“是”。我认为您正在搜索“今天是星期一和星期二” (2认同)

Cir*_*四事件 20

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

因为N1265 C99标准草案在6.7.2.2/3"枚举说明符"中明确允许:

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

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

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

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

  • 没有地址可以区分它们: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;
}
Run Code Online (Sandbox Code Playgroud)

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

gcc -c -g -O0 -std=c89 main.c
objdump -Sr main.o
Run Code Online (Sandbox Code Playgroud)

输出包含:

    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
Run Code Online (Sandbox Code Playgroud)

所以我们看到:

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


Ale*_*ino 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
};
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的代码中做:

for (int i = SLOT_FIRST; i <= SLOT_LAST; ++i) { }
Run Code Online (Sandbox Code Playgroud)


Jen*_*ens 8

它是哲学的(或不是)

#define ZILCH 0
#define NADA  0
Run Code Online (Sandbox Code Playgroud)

有许多用途,让不同的名称产生相同的数字是有意义的.