枚举类型检查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
的类型,以及两个名为apple
和orange
枚举器。
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 fruit
和struct 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 long
, gcc
也不会发出警告。
这是因为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
。