为什么 C 允许使用枚举作为变量?

Why does C allow the use of enum as a variable?

C 如何编译并 运行 下面的代码没有错误?

#include <stdio.h>

enum
{
    DETAILS_A                       =0x00U,
    DETAILS_B                       =0x01U,
    DETAILS_C                       =0x02U
}u8_Details;

int main()
{
    
    u8_Details = 42;
    
    printf("%d\n\n", u8_Details);
    
    printf("%d", DETAILS_B);

    return 0;
}

控制台输出:

42

1

...Program finished with exit code 0
Press ENTER to exit console

如果我没有理解错的话,就像下面这行:

u8_Details = 42;

相当于这个:

u8_Details u8_Details = 42;

但这似乎是错误的。我错过了什么?

在此声明中

enum
{
    DETAILS_A                       =0x00U,
    DETAILS_B                       =0x01U,
    DETAILS_C                       =0x02U
}u8_Details;

您在文件范围内声明了未命名枚举类型的变量u8_Details

您可以像为任何其他可变变量一样为变量赋值。

至于你的假设

u8_Details u8_Details = 42;

那就错了。 u8_Details 不是类型说明符。它是一个未命名枚举类型的变量的标识符。

u8_Details 不是枚举(类型)而是该枚举(类型)的变量。

enum {...} foo;

是变量定义语句。 enum {...} 是类型,foo 是标识符。

如果你想让 foo 成为一个类型,使用 typedef:

typedef enum {...} foo; /* foo is an alias of type enum {...} now */
foo bar; /* bar is of type foo */

Vlad 正确回答了问题,但我想补充一点:

C 有四个不同的名称空间 用于标识符:

  • 标签名称(由 goto: 消除歧义);
  • 标签名称(由 structunionenum 消除歧义);
  • structunion 成员名称(由 .-> 运算符消除歧义并出现在定义中);
  • 所有其他标识符(变量名、函数名、typedef 名、枚举常量等);

同一标识符可以在同一范围内的不同名称空间中使用-IOW,以下是完全合法的(只是确实不好的做法):

int main( void )
{
  struct foo {   // tag namespace
  {
    int foo;     // member namespace
    int bar;
  } foo;         // all other identifiers namespace
  
  goto foo;      // label namespace
  ...
  foo:           // label namespace
  foo.foo = 1;   // all other identifiers and member namespaces
  ...
}

标识符foo可以用作struct标签名、struct成员名、标签和变量名,都在同一范围内。

每个 structunion 定义都会创建一个新的成员命名空间,因此您可以在不同的 structunion 中使用 foo 作为成员名称定义:

 struct a { int foo; ... };
 struct b { double foo; ... };

枚举常量和typedef名称属于“所有其他标识符”命名空间,因此如果您将foo用作枚举常量,则不能同时将其用作常规变量名称或函数名称或typedef名称在同一范围内(反之亦然)。

只有一个标签命名空间,因此您不能在同一范围内对 struct 类型和 union 类型使用相同的标签名称 - IOW,如果您有 struct foo,您不能在同一范围内同时拥有 union fooenum foo