请参阅下面的简单示例。当返回一个
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
、char
甚至与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
决定不发出警告(clang
也是如此),但icc
(英特尔编译器)会在这种情况下发出警告。如果您想要对 enum
类型进行一些额外的类型检查,您可以将代码传递给一些静态代码检查器软件,例如 Lint
,它能够在这种情况下发出警告。
gcc
决定警告 enum
类型之间的隐式转换没有用,但还要注意,C 不需要实现在两个不同 enum
类型之间进行赋值时发出诊断。这与任何算术类型之间的分配相同:C 不需要诊断。例如,如果将 gcc
分配给 long long
或将 char
分配给 ,
short
也不会发出警告。 long
。
那是因为 C 中的
enum
只是一组唯一的整数常量,这样您就不必使用 #define
一大堆常量。它不像 C++,您创建的 enum
属于特定类型。 C 就是这样。
还值得注意的是,用于表示
enum
值的实际大小取决于编译器。
这个问题提出 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();
C 中的枚举基本上像整数一样处理。这只是使用常量的更好方法。
// this would work as well
ftype = 1;
您还可以指定值:
enum color {
RED=0,GREEN,BLUE
} mycolor;
mycolor = 1; // GREEN
海湾合作委员会的家伙总是有理由不做某事。
将 clang 与选项一起使用
-Wenum-conversion -Wassign-enum
。