【问题标题】:enum type check in C/gccC/gcc 中的枚举类型检查
【发布时间】:2011-12-21 22:48:09
【问题描述】:

请参见下面的简单示例。当返回一个enum 的函数被分配给另一个enum 的变量时,即使使用gcc -Wall -pedantic,我也不会收到任何警告。为什么 C 编译器不能对 enums 进行类型检查?还是gcc 特定的?我现在无法访问任何其他编译器来试用它..

enum fruit {
APPLE,
ORANGE
};

enum color {
RED,
GREEN
};

static inline enum color get_color() {
    return RED;
}

int main() {
    enum fruit ftype;
    ftype = get_color();
}

【问题讨论】:

    标签: c gcc enums


    【解决方案1】:

    此声明:

    enum fruit {
        apple,
        orange
    };
    

    声明了三件事:一个名为 enum fruit 的类型,以及两个名为 appleorange 的枚举数。

    enum fruit 实际上是一个独特的类型。它与一些实现定义的整数类型兼容;例如,enum fruit 可能与 intchar 兼容,或者甚至与 unsigned long long(如果实现选择)兼容,只要所选类型可以表示所有值。

    另一方面,枚举数是int 类型的常量。事实上,有一个常见的技巧是使用裸 enum 声明来声明 int 常量而不使用预处理器:

    enum { MAX = 1000 };
    

    是的,这意味着常量apple,即使它被声明为enum fruit 定义的一部分,实际上并不是enum fruit 类型。造成这种情况的原因是历史性的。是的,将枚举数设为类型的常量可能更有意义。

    在实践中,这种不一致并不重要。在大多数情况下,离散类型(即整数和枚举类型)在很大程度上是可互换的,并且隐式转换通常会做正确的事情。

    enum fruit { apple, orange };
    enum fruit obj;      /* obj is of type enum fruit */
    obj = orange;        /* orange is of type int; it's
                            implicitly converted to enum fruit */
    if (obj == orange) { /* operands are converted to a common type */
        /* ... */
    }
    

    但结果是,如您所见,如果您使用与一种枚举类型相关联的常量,而您的意思是使用不同的枚举类型,编译器可能不会警告您。

    获得强类型检查的一种方法是将数据包装在结构中:

    enum fruit { /* ... */ };
    enum color { /* ... */ };
    struct fruit { enum fruit f; };
    struct color { enum color c; };
    

    struct fruitstruct color 是不同且不兼容的类型,它们之间没有隐式(或显式)转换。缺点是您必须明确引用.f.c 成员。 (大多数 C 程序员只是指望他们一开始就能把事情做好——结果好坏参半。)

    typedef 不会为您提供强类型检查;尽管有名称,但它会为现有类型创建别名,而不是新类型。)

    (C++中的规则有些不同。)

    【讨论】:

      【解决方案2】:

      可能我们大多数人都了解根本原因(“规范说它必须工作”),但我们也同意这是“C”领域中许多编程错误的原因,并且结构包装解决方法很严重.忽略诸如 lint 之类的附加检查器,这就是我们所拥有的:

      gcc (4.9): No warning available.
      microsoft cl (18.0): No warning available.
      clang (3.5): YES -Wenum-conversion
      

      【讨论】:

      • 欢迎 Apple/LLVM。我相信这 3 个编译器几乎涵盖了所有主要操作系统(iOS、Android、Microsoft、OSX),但任何其他有趣的更新都值得赞赏。我相信以前的帖子提到了 icc,但我无权访问。
      【解决方案3】:

      gcc 决定不发出警告(clang 也是如此),但icc(英特尔编译器)会在这种情况下发出警告。如果您想对enum 类型进行一些额外的类型检查,您可以将您的代码传递给一些静态代码检查器软件,例如Lint,它能够在这种情况下发出警告。

      gcc 决定警告enum 类型之间的隐式转换没有用,但还要注意,在两个不同的enum 类型之间分配的情况下,C 不需要实现发出诊断。这与任何算术类型之间的分配相同:C 不需要诊断。例如,如果将 long long 分配给 char 或将 short 分配给 @,gcc 也不会发出警告987654333@.

      【讨论】:

        【解决方案4】:

        那是因为 C 中的 enums 只是一组唯一的整数常量,这使您不必使用 #define 一大堆常量。它不像 C++,您创建的 enums 属于特定类型。 C 就是这样。

        还值得注意的是,用于表示 enum 值的实际大小取决于编译器。

        【讨论】:

          【解决方案5】:

          C 中的枚举基本上像整数一样处理。这只是使用常量的一种更好的方式。

            // this would work as well
            ftype = 1;
          

          您还可以指定值:

            enum color {
               RED=0,GREEN,BLUE
            } mycolor;
          
            mycolor = 1; // GREEN
          

          【讨论】:

            【解决方案6】:

            gcc 家伙总是有理由不做某事。

            使用带有选项-Wenum-conversion -Wassign-enum的clang。

            【讨论】:

            • 显然gcc 的人在被冒犯时也有理由投反对票。我想在这个网站上批评不被视为 PC。无论如何,我赞成,因为您提供了有关如何获得 enum 类型检查的有用信息,这是最初提出的一个问题。对我来说幸运的是,没有人可以否决我的评论。 ;-)
            • gcc 从第 10 版开始支持 -Wenum-conversion 选项。(我没有投反对票,但如果我投了票,那是因为第一句话。)
            【解决方案7】:

            在提出这个问题 10 年后,GCC 现在可以做到:

            gcc -Wextra main.c

            main.c: In function ‘main’:
            main.c:17:11: warning: implicit conversion from ‘enum color’ to ‘enum fruit’ [-Wenum-conversion]
               17 |     ftype = get_color();
            

            【讨论】:

              猜你喜欢
              • 2013-03-20
              • 2019-12-30
              • 1970-01-01
              • 2018-10-31
              • 1970-01-01
              • 2016-05-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多