2011-12-21 53 views
17

查看下面的简单示例。当返回一个enum的函数被分配给不同enum的变量时,即使使用gcc -Wall -pedantic,我也不会收到任何警告。为什么C编译器无法对enum进行类型检查?或者是gcc具体?我没有访问任何其他编译器现在就试试吧..在C/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(); 
} 

回答

26

此声明:

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

这是因为enum S IN C是简单的一组独特的整型常量,从而节省您不必#define一大堆的常量。它不像C++,你创建的enum是特定类型的。 C就是这样。

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

1

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

// this would work as well 
    ftype = 1; 

您也可以指定值:

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

    mycolor = 1; // GREEN 
3

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

gcc决定是不是要警告enum类型,但还要注意,C不要求实施问题的转让情况下的诊断两种不同类型的enum之间的隐式转换是有用的。这与任何算术类型之间的赋值相同:C不要求进行诊断。例如,如果将long long指定为charshortlong,则gcc也不会警告。

5

也许我们大多数人都明白其根本原因(“规范说它必须工作”),但我们也同意这是“C”域中存在很多编程错误的原因,并且结构包装解决方法是毛。忽略附加检查程序,如皮棉,这里是我们有:

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

所有冰雹苹果/ LLVM。我相信这3个编译器几乎涵盖了所有主要的操作系统(iOS,Android,Microsoft,OSX),但是还有其他有趣的更新。我相信以前的帖子提到icc,但我没有访问。 – 2015-02-12 17:57:02