枚举类型检查C/gcc

Man*_*har 18 c enums gcc

请参阅下面的简单示例.当一个函数返回一个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();
}
Run Code Online (Sandbox Code Playgroud)

Kei*_*son 27

本声明:

enum fruit {
    apple,
    orange
};
Run Code Online (Sandbox Code Playgroud)

声明了三件事:一个叫做的类型enum fruit,两个名为appleand的枚举器orange.

enum fruit实际上是一种独特的类型.它与某些实现定义的整数类型兼容; 例如,只要所选择的类型可以表示所有值,就可以与实现选择的内容enum fruit兼容int,char甚至使用unsigned long long.

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

enum { MAX = 1000 };
Run Code Online (Sandbox Code Playgroud)

是的,这意味着常量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 */
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

但结果是,正如您所见,如果您使用与一个枚举类型关联的常量,则编译器不太可能发出警告,而您的意思是使用不同的类型.

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

enum fruit { /* ... */ };
enum color { /* ... */ };
struct fruit { enum fruit f; };
struct color { enum color c; };
Run Code Online (Sandbox Code Playgroud)

struct fruit并且struct color是不同且不兼容的类型,它们之间没有隐式(或显式)转换.缺点是你必须明确地引用.f.c成员.(大多数C程序员只是依靠他们在第一时间把事情做好的能力 - 结果好坏参半.)

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

(C++中的规则略有不同.)


Pet*_*r M 5

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

gcc (4.9): No warning available.
microsoft cl (18.0): No warning available.
clang (3.5): YES -Wenum-conversion
Run Code Online (Sandbox Code Playgroud)