2014-04-27 130 views
13

根據§7.2/ 5和§7.2/ 6不應該code below打印1 1而不是4 4代碼不應該打印「1 1」而不是「4 4」?

#include <iostream> 
enum A { a = (char)1, b, c }; // underlying type is not fixed 

int main() { 
    std::cout << sizeof(a) << ' ' << sizeof(A) << '\n'; 
} 

編輯

從§7.2/ 5:

如果底層類型是不固定的,每個枚舉的類型是 其初始化值的類型:

- 如果爲枚舉器指定了初始值設定項,則初始值 的值與表達式的類型相同並且常數表達式 應該是積分常數表達式(5.19)。

+1

這兩個子句都沒有說明基礎類型必須儘可能小。 –

+0

@OliCharlesworth查看我的編輯 –

+0

我認爲「繼enum-specifier的大括號後,每個枚舉器都有其枚舉類型。」從§7.2/ 5也適用於具有非固定類型的枚舉。 [現場示例](http://coliru.stacked-crooked.com/a/cc6897fa1bfab56f) – dyp

回答

20

如果您沒有明確定義底層類型,那麼編譯器可以自由選擇適合這些值的整型。要設置基礎類型的C++ 11你可以使用這個:

enum A : char { a = 1, b, c }; 
     ^^^^^^ 

你的方式不會強迫編譯器char,而是如果int使用。

+1

你明白了!很好的回答(+1) –

5

這是實現定義的事實:一個enum的所有值適應,也就是說,一個uint8_t不強制編譯器挑選枚舉一個單字節表示。

枚舉的基礎類型是一個整型,它可以表示枚舉中定義的所有枚舉值。 它是實現定義的,整數類型用作枚舉的基礎類型,除非基礎類型不應大於int,除非枚舉器的值不適合int或unsigned int。 (強調)

你的情況看來,編譯器執行者選擇的int,這需要你的平臺上四個字節 - 一個完全有效的選擇。

4

您引用的條款7.2/5描述了的列表類型。但是普查員只構成列舉定義的一部分。基礎類型枚舉的是大到足以容納所有值枚舉,受7.2/6:

它是實現定義其積分類型用作底層類型不同的是,基礎類型不得大於int,除非枚舉數的值不適合intunsigned int

所以可以保證您的基礎類型不大於int的情況下(因爲int可以表示0,1和2)。確實,您的第一個枚舉數的類型在枚舉定義中爲char,但所有實際的枚舉值都是A類型。要實際控制基礎類型,請使用enum-base語法(例如enum A : char),並查詢它可以使用std::underlying_type特徵。

如果你真的想看到枚舉的定義中的類型的效果,你可以嘗試這樣的事:

enum Foo { a = '\010', b = sizeof(a) }; 

std::cout << typeid(b).name() << "\n"; // some variant of "Foo" 
std::cout << b << "\n";     // "1" 
std::cout << sizeof(b) << "\n";   // implementation-defined, not greater 
              // than sizeof(int) 
+0

*「的確,第一個枚舉器的類型是'char'」*直到枚舉的'}',看到我對OP的評論。 – dyp

+0

@dyp:恩,是的,枚舉器不是程序可用的東西。它只是作爲枚舉類型定義的一部分。 –

+0

咦?/11表示「每個* enum-name *和每個unscoped *枚舉器*在立即包含 *枚舉說明符*的範圍內聲明」。據我所知,這些常量是*枚舉*,即使您在枚舉聲明結束後訪問它們。 (後來在/ 11「在類範圍中聲明的枚舉數可以使用類成員訪問 運算符[......]」) – dyp

4

號從ANSI C開始,合規編譯器經常使用int來存儲枚舉,即使所有的值都很小。

在你說這是瘋了之前,它應該使用最小的工作類型(如果你使用__attribute__((packed)),GCC會這樣做),考慮一下ABI的兼容性。如果您釋放使用枚舉類型的庫,則希望該類型的大小不會更改。如果所有的枚舉都以4個字節開始,那麼可能會增加,只需重新鏈接更新的庫就可以工作。

+0

查看我的編輯以上 –

+1

我希望語言設計人員允許程序員根據* requirements *指定類型。如果一個類型需要保持0-50,000的值並且必須緊湊地存儲,但是包裝行爲並不重要,在許多處理器上,當存儲在存儲器存儲器中時最好是「uint16_t」,而當存儲在存儲器中時最好是「uint32_t」保存在註冊表中。如果需要包裝mod 4,294,967,296的東西,那麼它應該包裝mod 4,294,967,296,而不管機器的原始字大小如何。一種語言讓程序員指定需求越好,各種使用情況下需要的妥協就越少。 – supercat

相關問題