如果我有这样的枚举:
enum EnumA
{
stuffA = 0
};
enum enumAA
{
stuffA = 1
};
当您引用stuffA
时会发生什么?我认为你会像Java一样将它们称为EnumA.stuffA
和EnumB.stuffA
,但在C中似乎并非如此。
答案 0 :(得分:9)
enums
不引入新范围。
在您的示例中,由于enum
名称冲突,第二个stuffA
无法编译。
为避免名称冲突,通常的做法是为enum
提供一个共同前缀的元素。不同的前缀将用于不同的枚举:
enum EnumA
{
EA_stuffA = 0
};
enum EnumAA
{
EAA_stuffA = 1
};
答案 1 :(得分:7)
枚举常量位于全局名称空间中(更确切地说,普通标识符名称空间,与标签,标记和结构/联合成员名称空间形成对比),因此您会收到编译错误在第二个stuffA
。
在单个翻译单元中,不能对同一枚举名称使用两个不同的值(也不能使用两次指定的相同值)。
答案 2 :(得分:6)
正如其他人已经说过的,枚举常量在定义它们的实际范围内必须是唯一的。但与其他标识符一样,它们可以在另一个范围内重新定义它们。例如
enum EnumA
{
stuffA = 0
};
void func(void) {
enum enumAA
{
stuffA = 1
};
// do something
}
没关系。但是在不同范围内的这种重新定义往往是不受欢迎的,应该有很好的文档记录,否则你会很快失去自己和他人。
答案 3 :(得分:1)
如上所述,这将无法编译,因为stuffA定义了两次。枚举值简单地用枚举引用(即“stuffA”而不是EnumA.stuffA)。您甚至可以在非枚举类型(例如整数)上使用它们。枚举有时以这种方式使用整数,类似于#define常量的方式。
答案 4 :(得分:0)
此答案显示了C 2018的规则如何防止将相同的标识符用作两个不同枚举的成员。这是一种语言律师视图,旨在说明此要求是如何从标准的语言中产生的。
6.2.3,“标识符的名称空间”告诉我们:
如果在翻译单元中的任何位置都可以看到一个以上的特定标识符声明,则语法上下文会消除指向不同实体的用法的歧义。因此,对于各种类别的标识符,存在单独的名称空间,如下所示:
...
-所有其他标识符,称为普通标识符(在普通声明符中声明为枚举常量)。
因此,所有枚举常量和普通声明符都存在于一个名称空间中。 (上面省略的名称空间用于 labels [用于goto
语句];结构,联合和枚举的 tags [{{1}之后的名称},例如struct
;以及结构或联合体的成员 [每个成员都有其自己的命名空间]。
6.7“声明”在第5段中告诉我们:
标识符的定义是对该标识符的声明,该声明:
...
对于枚举常量,是标识符的(唯一)声明;
...
因此,该标准表明枚举常数只有一个定义。此外,第6.2.1节“标识符的范围”在第1段中告诉我们:
标识符可以表示一个对象;功能;标签,结构,联合或枚举的成员; typedef名称;标签名称;宏名称;或宏参数。相同的标识符可以表示程序中不同点的不同实体。枚举的成员称为枚举常量。
可以看出,这表明struct foo
标识了枚举常量,它标识了枚举的成员,它是特定枚举的特定成员。它不能同时标识foo
的成员和enum A
的成员。因此,如果我们有以下代码:
enum B
第二次出现enum A { foo = 1 };
enum B { foo = 1 };
时,它是foo
中foo
的标识符,因此它不能是enum A
的成员。
(关于在不同点表示不同实体的标识符的句子引入了 scope 的概念。该节的其他段落解释了范围的概念以及四种范围:函数,文件,块和函数原型。这些不会影响以上分析,因为上面的代码在一个范围内。)
答案 5 :(得分:-1)
根据您声明这些枚举的位置,您还可以使用namespace关键字声明新范围。
注意:我不建议这样做,我只是注意到它是可能的。 相反,最好使用其他示例中提到的前缀。
namespace EnumA
{
enum EnumA_e
{
stuffA = 0
};
};
namespace EnumAA
{
enum enumAA_e
{
stuffA = 1
};
};