【问题标题】:Is there no problem using enumeration without declaration of enum variable in C?在C中没有声明枚举变量的情况下使用枚举没有问题吗?
【发布时间】:2020-09-12 23:20:21
【问题描述】:

我对枚举类型变量和 int 类型变量在 C 中的工作方式有何不同感到困惑。

我听说在 C++ 中枚举类型和整数类型之间可能存在转换错误,但 C 没有。

那么如果C中的整数变量和枚举类型变量没有区别, 我可以只声明枚举名称并使用它们而不声明任何枚举类型变量吗,例如,

 ...

 enum { WIN, LOSE, DRAW };

 int main() {

     int result;

     result = play_game(...);

     if (result == WIN) { ... }
     else if (result == LOSE) { ... }
     ...

 }

 int play_game(...) {
     ...
     if (...)       return WIN;
     else if (...)  return LOSE;
     else           return DRAW;
     ...
 }

如上。 (只是为了提高可读性,而不是使用无意义的数字;01210-1 等)

实际上,我无法理解声明特定枚举类型变量的含义,如下所示。

 enum GameResult { WIN, LOSE, DRAW } result;

这是否也与代码可读性有关? 我的意思是,将 result 声明为 int 和枚举类型变量之间有什么区别?

【问题讨论】:

  • 这能回答你的问题吗? How to define an enumerated type (enum) in C?
  • 这能回答你的问题吗? Why use enum when #define is just as efficient?
  • enum 是一组常量的容器,它会自动为枚举中的每个常量分配下一个 +1 值,在您的示例中,您没有为枚举命名,它的作用类似于命名空间并将常量分组到指定的名称下。使用枚举的主要好处是可以检查有效值。
  • 为枚举声明类型名称允许您定义该类型的函数参数和变量,应该只采用枚举中定义的值之一。您当然可以在代码中使用未命名的枚举值,但是如果您有多个不同的未命名枚举,则无法使用枚举类型定义变量或函数参数。

标签: c enums


【解决方案1】:

是的,在枚举中声明的标识符可以用作普通的 int 常量,根据 C 2018 6.4.4.3 2:“声明为枚举常量的标识符具有类型 int”和 6.7.2.2 3:“The枚举器列表中的标识符被声明为类型为 int 的常量,并且可以出现在任何允许的地方。”

我的意思是,将result 声明为 int 和枚举类型变量之间有什么区别?

虽然枚举常量的类型为int,但枚举对象(变量)可能具有其他整数类型。根据 6.7.2.2 4,它是实现定义的。

这些意味着int 值可能被分配给枚举对象,因此在处理枚举时会阻碍强类型化,尽管编译器可以尝试进行一些检查并提供警告。

【讨论】:

    【解决方案2】:

    是的,枚举基本上是int 替换。但是,您发布的代码存在一些最佳实践问题。这个问题是主观的,尽管它被广泛认为是在 C 编程中避免“幻数”的良好做法。

    也就是说,您不应该编写一个返回 int012 的函数。那将是一个相当神秘的界面。但是在不改变返回类型的情况下用enum 替换那些“神奇的数字”是草率的。它不应该返回int,而是你应该使用typedef,例如:

    typedef enum { WIN, LOSE, DRAW } game_result_t;
    ...
    game_result_t play_game(...)
    

    这为您提供了一种仅用于此特定目的的特殊类型。它提高了可读性并且(可以说)增加了一点点类型安全性。

    更好的是,以相同的方式为枚举值、函数和所有内容添加前缀,以便读者可以分辨出哪些项目属于一起:

    // game.h
    
    typedef enum { GAME_WIN, GAME_LOSE, GAME_DRAW } game_result_t;
    ...
    game_result_t game_play (...)
    

    现在game.h 中的所有内容都以game_ 为前缀,这样可以轻松找出某个常量或函数的来源,而无需挖掘/搜索代码。

    【讨论】:

    • 感谢您的友好解释。正如您所提到的'一点点类型安全',如果返回类型为game_result_t 的函数返回一个整数常量(如12),是否有任何安全警告?或者是否有任何进一步的技术可以防止意外的类型转换?
    • @studio-luke 由编译器和/或静态分析器工具来显示此类类型兼容性消息 - 标准中没有任何规定。就 C 标准而言,至少在理论上,可以非常广泛地混合不同大小和符号的整数类型。不过,该语言有所谓的“安全子集”,例如 MISRA-C,它对枚举类型安全有更严格的规则,并且使用 typedef 可能更容易使代码兼容。
    【解决方案3】:

    是的,枚举经常用于提高可读性。默认情况下,枚举中的第一个值为 0。它们确实像 const 数组。

     enum GameResult { WIN, LOSE, DRAW } result;
    

    我不建议使用它,因为不清楚结果是 8 位、16 位还是其他值以及何时会导致溢出。

    【讨论】:

    • 同意您避免使用类型(尤其是作为函数参数)的观点,因为大小未知
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多