2011-12-21 97 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