2008-10-01 74 views
92

C++枚舉是帶符號還是無符號?通過擴展來驗證輸入是安全的,通過檢查它是< =您的最大值,並且忽略> =您的最小值(假設您從0開始並增加1)?C++枚舉是已簽名還是未簽名?

+0

當我們使用一個背景,它要求它的標誌枚舉類型,我們實際上是在談論枚舉隱含轉換爲整型。 C++ 03標準說這是通過Integral Promotion完成的,與枚舉的基礎類型沒有任何關係。所以,我不明白爲什麼這裏的每個答案都提到標準沒有定義的底層類型?我在這裏描述了預期的行爲:http://stackoverflow.com/questions/24802322/sign-of-c-enum-type-in​​correct-after-converting-to-integral-type – JavaMan 2014-07-17 12:10:30

回答

56

您不應該依賴任何特定的表示形式。閱讀以下link。此外,該標準說,它是實現定義的哪種整數類型用作枚舉的基礎類型,除非它不應大於int,除非某些值不適合int或unsigned int。

簡而言之:你不能依賴一個有符號或無符號的枚舉。

+21

[Michael Burr的回答](http:///stackoverflow.com/a/159308/594137)(其中引用標準)實際上意味着如果您將枚舉值定義爲負數,則可以依靠它進行簽名,因爲類型能夠「表示所有定義的枚舉器值在列舉中「。 – 2012-12-11 08:20:25

4

編譯器可以決定枚舉是否有符號或無符號。

驗證枚舉的另一種方法是使用枚舉本身作爲變量類型。例如:

enum Fruit 
{ 
    Apple = 0, 
    Banana, 
    Pineapple, 
    Orange, 
    Kumquat 
}; 

enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum 
fruitVariable = 1; // Error, 1 is not a member of enum Fruit even though it has the same value as banana. 
19

您不應該依賴它們被簽名或未簽名。如果你想使他們明確符號或無符號,你可以使用以下命令:

enum X : signed int { ... }; // signed enum 
enum Y : unsigned int { ... }; // unsigned enum 
+10

只有在未來的C++ 0x標準。 – dalle 2008-10-01 18:51:22

+3

@dalle Microsoft編譯器還允許鍵入枚舉 http://msdn.microsoft.com/en-us/library/2dzy4k6e(v=vs.80).aspx – teodozjan 2012-10-08 12:37:25

3

在未來,隨着的C++ 0x,strongly typed enumerations將可用,並且有幾個優點(如類型安全,顯基礎類型或顯式範圍)。有了這個,你可以更好地確定這種類型的標誌。

95

讓我們來源。下面介紹一下C++標準03(ISO/IEC 14882:2003)文檔中7.2-5說(枚舉聲明):

基礎類型的枚舉 的是能夠代表 所有整型在枚舉中定義的枚舉值在 中定義。它是 實現定義其積分 類型用作底層類型 用於枚舉不同的是 基礎類型不得大於INT較大 除非 枚舉的值可以不適合在int或 無符號整型。

總之,您的編譯器可以選擇(顯然,如果您的某些ennumeration值有負數,它將被簽名)。

+0

我們如何避免編譯器猜測並告訴它使用底層所有枚舉值都是小的正整數時的無符號類型? (我們正在捕捉一個UBsan的發現,因爲編譯器正在挑選一個int,並且int的溢出,這個值是無符號和正數的,我們的使用依賴於unsigned wrap來提供遞減或「負跨度」)。 – jww 2017-12-16 18:40:57

+0

@jww - 這將取決於你正在使用什麼編譯器,我猜。由於該標準沒有規定底層類型,並將其留給實現,因此需要查看工具的文檔並查看是否可以使用該選項。如果你想保證代碼中的某些行爲,爲什麼不在表達式中使用enum成員呢? – ysap 2018-02-09 12:42:56

12

您不應該依賴它是有符號還是無符號。根據標準,它是實現定義的,其中整型被用作枚舉的基礎類型。但是在大多數實現中,它是一個有符號的整數。

在C++ 0X strongly typed enumerations將被添加,這將允許用戶指定一個枚舉的類型,例如:

enum X : signed int { ... }; // signed enum 
enum Y : unsigned int { ... }; // unsigned enum 

即使是現在,雖然,一些簡單的驗證可以通過使用作爲枚舉實現一個變量或參數類型是這樣的:

enum Fruit { Apple, Banana }; 

enum Fruit fruitVariable = Banana; // Okay, Banana is a member of the Fruit enum 
fruitVariable = 1; // Error, 1 is not a member of enum Fruit 
        // even though it has the same value as banana. 
3

除了別人已經說過符號/無符號,這裏就是標準說,大約一個枚舉類型的範圍:

7.2(6):「對於e(min)是最小枚舉數且e(max)最大的枚舉,枚舉值是範圍b(min)到b (max),其中b(min)和b(max)分別是可以存儲e(min)和e(max)的最小位域的最小值和最大值。它可以定義具有不受任何其枚舉的定義的值的枚舉「

因此,例如:。

enum { A = 1, B = 4}; 

定義枚舉類型,其中e(分鐘)爲1和e(最大)是4.如果底層類型是帶符號的int,那麼最小的所需位域有4位,如果實現中的整數是二進制補碼,那麼枚舉的有效範圍是-8到7.如果底層類型是無符號的,那麼它有3位,範圍是0到7.檢查你的編譯器文檔,如果你關心的話(例如,如果你想將枚舉類型之外的整型值轉換爲枚舉類型,那麼你需要知道該值是否在枚舉與否 - 如果不是,則生成的枚舉值未指定)。

無論這些值是否爲有效的函數輸入,可能與它們是否爲枚舉類型的有效值不同。你的檢查代碼可能擔心前者而不是後者,因此在這個例子中至少應該檢查> = A和< = B。

4

即使一些舊的答案有44個upvotes,我傾向於不同意他們所有人。總之,我不認爲我們應該關心enum的underlying type

首先,C++ 03枚舉類型是它自己的獨特類型,沒有符號概念。由於從C++ 03標準dcl.enum

7.2 Enumeration declarations 
5 Each enumeration defines a type that is different from all other types.... 

所以,當我們在談論一個枚舉類型的標誌,說使用<操作比較2個枚舉操作數的時候,我們實際上是在談論隱式枚舉類型轉換爲一些整體類型。 這是整體類型的標誌,重要的是。當將enum轉換爲整數類型時,此語句適用:

9 The value of an enumerator or an object of an enumeration type is converted to an integer by integral promotion (4.5). 

而且,顯然,枚舉的基本類型與Integral Promotion無關。由於標準定義積分促進這樣的:

4.5 Integral promotions conv.prom 
.. An rvalue of an enumeration type (7.2) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration 
(i.e. the values in the range bmin to bmax as described in 7.2: int, unsigned int, long, or unsigned long. 

所以,枚舉類型是否變爲signed intunsigned int取決於signed int是否可以包含所定義的枚舉,而不是基本的類型枚舉的所有的值。

見我相關的問題 Sign of C++ Enum Type Incorrect After Converting to Integral Type