为什么 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
和 :
消除歧义);
- 标签名称(由
struct
、union
或 enum
消除歧义);
struct
和 union
成员名称(由 .
或 ->
运算符消除歧义并出现在定义中);
- 所有其他标识符(变量名、函数名、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
成员名、标签和变量名,都在同一范围内。
每个 struct
或 union
定义都会创建一个新的成员命名空间,因此您可以在不同的 struct
或 union
中使用 foo
作为成员名称定义:
struct a { int foo; ... };
struct b { double foo; ... };
枚举常量和typedef名称属于“所有其他标识符”命名空间,因此如果您将foo
用作枚举常量,则不能同时将其用作常规变量名称或函数名称或typedef名称在同一范围内(反之亦然)。
只有一个标签命名空间,因此您不能在同一范围内对 struct
类型和 union
类型使用相同的标签名称 - IOW,如果您有 struct foo
,您不能在同一范围内同时拥有 union foo
和 enum foo
。
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
和:
消除歧义); - 标签名称(由
struct
、union
或enum
消除歧义); struct
和union
成员名称(由.
或->
运算符消除歧义并出现在定义中);- 所有其他标识符(变量名、函数名、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
成员名、标签和变量名,都在同一范围内。
每个 struct
或 union
定义都会创建一个新的成员命名空间,因此您可以在不同的 struct
或 union
中使用 foo
作为成员名称定义:
struct a { int foo; ... };
struct b { double foo; ... };
枚举常量和typedef名称属于“所有其他标识符”命名空间,因此如果您将foo
用作枚举常量,则不能同时将其用作常规变量名称或函数名称或typedef名称在同一范围内(反之亦然)。
只有一个标签命名空间,因此您不能在同一范围内对 struct
类型和 union
类型使用相同的标签名称 - IOW,如果您有 struct foo
,您不能在同一范围内同时拥有 union foo
和 enum foo
。