枚举类型检查C / gcc

请参阅下面的简单示例。 当一个函数返回一个enum被分配给一个不同enum的变量时,即使使用gcc -Wall -pedantic我也不会收到任何警告。 为什么C编译器不能对enum进行类型检查? 或者是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(); } 

本声明:

 enum fruit { apple, orange }; 

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

enum fruit实际上是一种独特的类型。 它与某些实现定义的整数类型兼容; 例如, enum fruit可能与int兼容,或者甚至与实现选择的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 ++中的规则略有不同。)

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

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

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

gcc认为警告enum类型之间的隐式转换是没有用的,但是请注意,在两种不同的enum类型之间进行赋值的情况下,C不要求实现发出诊断。 这与任何算术类型之间的赋值相同:C不需要诊断。例如,如果将long long分配给char或将short分配给long longgcc也不会发出警告。

这是因为C中的enum只是一组唯一的整数常量,这使您无需#define一大堆常量。 它不像C ++,你创建的enum是特定类型。 这就是C的方式。

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

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

  // this would work as well ftype = 1; 

您还可以指定值:

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

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

使用clang和选项-Wenum-conversion -Wassign-enum