簡體   English   中英

C++ 枚舉是有符號的還是無符號的?

[英]Are C++ enums signed or unsigned?

C++ 枚舉是有符號的還是無符號的? 通過擴展,通過檢查輸入是 <= 您的最大值,並忽略 >= 您的最小值(假設您從 0 開始並以 1 遞增)來驗證輸入是否安全?

讓我們回到源頭。 以下是 C++03 標准 (ISO/IEC 14882:2003) 文檔在 7.2-5(枚舉聲明)中的說明:

枚舉的基礎類型是可以表示枚舉中定義的所有枚舉器值的整數類型。 使用哪種整數類型作為枚舉的底層類型是實現定義的,除非底層類型不應大於 int,除非枚舉數的值不能適合 int 或 unsigned int。

簡而言之,您的編譯器可以選擇(顯然,如果您的某些枚舉值有負數,則它將被簽名)。

你不應該依賴任何特定的表示。 閱讀以下鏈接 此外,該標准表示,它是實現定義的,哪種整數類型用作枚舉的基礎類型,但它不應大於 int,除非某些值不能放入 int 或無符號 int。

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

您不應該依賴於它們是否已簽名或未簽名。 如果要使它們顯式簽名或未簽名,可以使用以下命令:

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

你不應該依賴它是簽名的還是未簽名的。 根據標准,實現定義了哪種整數類型用作枚舉的基礎類型。 但是,在大多數實現中,它是一個有符號整數。

在 C++0x 中,將添加強類型枚舉,這將允許您指定枚舉的類型,例如:

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.

即使是一些舊的答案也得到了 44 票,我傾向於不同意所有這些答案。 簡而言之,我認為我們不應該關心枚舉的underlying type

首先,C++03 Enum 類型是一種獨特的類型,沒有符號概念。 從 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 無關。 由於標准定義了 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

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

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

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.

將來,在 C++0x 中, 強類型枚舉將可用並具有多個優點(例如類型安全、顯式底層類型或顯式范圍)。 這樣您就可以更好地確定類型的符號。

除了其他人已經說過的關於有符號/無符號的內容之外,以下是標准關於枚舉類型范圍的內容:

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(min) 為 1,e(max) 為 4。如果基礎類型是有符號 int,則所需的最小位域有 4 位,如果您的實現中的 int 是二進制補碼,則有效范圍為枚舉是 -8 到 7。如果基礎類型是無符號的,那么它有 3 位,范圍是 0 到 7。如果您關心,請檢查您的編譯器文檔(例如,如果您想將除枚舉數以外的整數值轉換為枚舉類型,那么您需要知道該值是否在枚舉范圍內 - 如果不是,則結果枚舉值未指定)。

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

使用std::is_signed<std::underlying_type + 范圍枚舉默認為int檢查它

https://en.cppreference.com/w/cpp/language/enum暗示:

主程序

#include <cassert>
#include <iostream>
#include <type_traits>

enum Unscoped {};
enum class ScopedDefault {};
enum class ScopedExplicit : long {};

int main() {
    // Implementation defined, let's find out.
    std::cout << std::is_signed<std::underlying_type<Unscoped>>() << std::endl;

    // Guaranteed. Scoped defaults to int.
    assert((std::is_same<std::underlying_type<ScopedDefault>::type, int>()));

    // Guaranteed. We set it ourselves.
    assert((std::is_same<std::underlying_type<ScopedExplicit>::type, long>()));
}

GitHub 上游.

編譯並運行:

g++ -std=c++17 -Wall -Wextra -pedantic-errors -o main main.cpp
./main

輸出:

0

在 Ubuntu 16.04、GCC 6.4.0 上測試。

雖然上面的一些答案可以說是正確的,但它們並沒有回答我的實際問題。 編譯器 (gcc 9.3.0) 發出警告:

enum FOO_STATUS {
    STATUS_ERROR = (1 << 31)
};

使用時發出警告:

unsigned status = foo_status_get();
if (STATUS_ERROR == status) {

(除了這個代碼不正確的事實......不要問。)

當正確詢問時,編譯器不會發出錯誤。

enum FOO_STATUS {
    STATUS_ERROR = (1U << 31)
};

請注意, 1U使表達式無符號。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM