【问题标题】:Enumeration Scope枚举范围
【发布时间】:2011-12-09 15:45:02
【问题描述】:

如果我有这样的枚举:

enum EnumA
{
  stuffA = 0
};
enum enumAA
{
  stuffA = 1
};

当您引用stuffA 时会发生什么?我以为你会像在 Java 中那样将它们称为 EnumA.stuffAEnumB.stuffA,但在 C 中似乎并非如此。

【问题讨论】:

    标签: c enums


    【解决方案1】:

    enums 不引入新作用域。

    在您的示例中,由于 stuffA 名称冲突,第二个 enum 无法编译。

    为避免名称冲突,通常的做法是为enum 的元素提供一个公共前缀。不同的前缀将用于不同的枚举:

    enum EnumA
    {
      EA_stuffA = 0
    };
    enum EnumAA
    {
      EAA_stuffA = 1
    };
    

    【讨论】:

    • 那么,如果我想完成类似上述的事情(狭窄的范围),结构会是我唯一/最好的选择吗?
    • 你必须使用一些东西:enum enumA { enumA_stuffA = 0 }; enum enumAA { enumAA_stuffA = 1 };
    【解决方案2】:

    枚举常量在全局命名空间中(更准确地说,普通标识符命名空间,与标签、标签和结构/联合成员命名空间形成对比),所以你会得到一个编译错误在第二个stuffA

    您不能在单个翻译单元中为同一个枚举名称使用两个不同的值(也不能两次指定相同的值)。

    【讨论】:

      【解决方案3】:

      正如其他人已经说过的,枚举常量在定义它们的实际范围内必须是唯一的。但是对于它们和其他标识符一样,允许在另一个范围内重新定义它们。例如。

      enum EnumA
      {
        stuffA = 0
      };
      
      void func(void) {
         enum enumAA
         {
           stuffA = 1
         };
         // do something
      }
      

      会好的。但是这种在不同范围内的重新定义往往是不受欢迎的,应该有据可查,否则你很快就会失去自己和他人。

      【讨论】:

      • +1 幸运的是,带有-Wshadow 的 gcc 提供了warning: declaration of 'stuffA' shadows a global declaration
      【解决方案4】:

      如前所述,这不会编译,因为 stuffA 被定义了两次。枚举值仅由枚举引用(即“stuffA”而不是 EnumA.stuffA)。您甚至可以在非枚举类型(例如整数)上使用它们。枚举有时会以这种方式与整数一起使用,类似于 #define 常量的方式。

      【讨论】:

      • 在 C 中,enum 常量 int 根据标准的定义。
      【解决方案5】:

      这个答案显示了 C 2018 的规则如何阻止相同的标识符被用作两个不同枚举的成员。这是一种语言律师的观点,旨在说明这一要求是如何从标准的语言中产生的。

      6.2.3,“标识符的命名空间”告诉我们:

      如果一个特定标识符的多个声明在翻译单元中的任何位置可见,则句法上下文消除了引用不同实体的用法的歧义。因此,不同类别的标识符有单独的名称空间,如下所示:

      ——所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量声明)。

      因此,所有枚举常量和普通声明符都存在于一个名称空间中。 (上面省略的名称空间用于 labels [for goto statements];tags 结构、联合和枚举 [struct 之后的名称,如struct foo];以及结构或联合的成员 [每个都有自己的名称空间])。

      6.7,“声明”,第 5 段告诉我们:

      标识符的定义是该标识符的声明:

      对于枚举常量,是标识符的(唯一)声明;

      所以标准表明枚举常量只有一个定义。此外,6.2.1,“标识符的范围”,在第 1 段中告诉我们:

      一个标识符可以表示一个对象;一个函数;结构、联合或枚举的标签或成员;类型定义名称;标签名称;宏名;或宏参数。同一个标识符可以在程序的不同点表示不同的实体。枚举的成员称为枚举常量

      请注意,这表明如果foo 标识了一个枚举常量,它就标识了一个枚举成员——它是一个特定枚举的特定成员。它不能同时识别enum A 的成员和enum B 的成员。因此,如果我们有代码:

      enum A { foo = 1 };
      enum B { foo = 1 };
      

      foo第二次出现时,它是enum Afoo的标识符,因此它不能是enum B的成员。

      (关于标识符在不同点表示不同实体的句子是引入范围的概念。该子句中的其他段落解释了范围的概念和四种范围:函数、文件、块和函数原型。这些不影响上面的分析,因为上面的代码在一个范围内。)

      【讨论】:

        【解决方案6】:

        根据您声明这些枚举的位置,您还可以使用命名空间关键字声明新范围。

        注意:我不建议这样做,我只是注意到这是可能的。 相反,最好使用其他示例中提到的前缀。

        namespace EnumA
        {
            enum EnumA_e
            {
                stuffA = 0
            };
        };
        
        namespace EnumAA
        {
            enum enumAA_e
            {
                stuffA = 1
            };
        };
        

        【讨论】:

        • C 中没有命名空间,这是 C++
        猜你喜欢
        • 1970-01-01
        • 2011-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-06
        • 1970-01-01
        • 1970-01-01
        • 2017-04-21
        相关资源
        最近更新 更多