枚举

出自cppreference.com


枚舉類型 是獨立的類型,其值為包含所有其顯示命名的常量(枚舉常量)的底層類型 的值。

語法

枚舉類型在聲明文法中以跟隨的枚舉說明符 作為類型說明符 聲明:

enum 屬性聲明符序列 (可選) 標識符 (可選) { 枚舉項列表 } (1)
enum 屬性聲明符序列 (可選) 標識符 (可選) : 類型 { 枚舉項列表 } (2) (C23 起)
1) 聲明沒有固定底層類型的枚舉。
2) 聲明固定底層類型為類型 的枚舉。

其中枚舉項列表 是枚舉項 的逗號分隔列表(允許尾隨的逗號)(C99 起),每個枚舉項 擁有形式:

枚舉常量 屬性聲明符序列 (可選) (1)
枚舉常量 屬性聲明符序列 (可選) = 常量表達式 (2)

其中

標識符, 枚舉常量 - 由此聲明引入的標識符
常量表達式 - 整數常量表達式其值可以以 int 類型的值表示。(C23 前)若枚舉具有固定底層類型,則其可以表示為類型 的值(C23 起)
屬性聲明符序列 - (C23)可選的屬性列表
  • 若出現在 enum 後則應用到整個枚舉,
  • 若出現在枚舉常量  後則應用到枚舉項 

結構體聯合體一樣,引入枚舉類型和一或多個枚舉常量的聲明亦可聲明一或多個該類型的對象,或從該類型派生的類型的對象。

enum color_t {RED, GREEN, BLUE} c = RED, *cp = &c;
// 引入类型 enum color_t
// 整数常量 RED 、 GREEN 、 BLUE 
// 对象 c 拥有类型 enum color_t
// 对象 cp 的类型为指向 enum color_t 的指针

解釋

每個出現於枚舉說明符體中的枚舉常量 會成為 int 類型的(C23 前)整數常量,並處於包圍它的作用域中,而且在凡要求整數常量處可用(例如,作為 case 標號或非 VLA 數組大小)。

在處理枚舉項列表中的每個枚舉常量過程中,枚舉常量的類型應當為:

  • 之前聲明的類型,若此為相同枚舉常量的重聲明;或者,
  • 對於帶有固定底層類型的枚舉,則為枚舉所用類型;或者,
  • int,若枚舉項列表中沒有更早的枚舉常量且沒有提供定義的整數常量表達式的明確 =;或者,
  • int,若給出了明確的 = 且整數常量表達式的值可以表示為 int;或者,
  • 整數常量表達式的類型,若給出了明確的 = 並且整數常量表達式的值無法表示為 int;或者,
  • 最後一個沒寄出來的值加上 1 的值的類型。如果這種整數常量表達式對於前一個枚舉常量加 1 的值會發生溢出或迴繞,則其類型為以下之一:
    • 適當大小的有符號整數類型(不包括位精確有符號整數類型),有能力表示前一個枚舉常量加 1 的值;或者
    • 適當大小的無符號整數類型(不包括位精確無符號整數類型),有能力表示前一個枚舉常量加 1 的值。

當被加的前一個枚舉常量為有符號整數類型時,選用有符號整數類型。當被加的前一個枚舉常量為無符號整數類型時,選用無符號整數類型。如果不存在前述可以表示新值的合適的有符號整數類型,則該枚舉沒有有能力表示其所有值的類型。

(C23 起)
enum color { RED, GREEN, BLUE } r = RED;
switch(r)
{
case RED:
    puts("red");
    break;
case GREEN:
    puts("green");
    break;
case BLUE:
    puts("blue");
    break;
}

枚舉常量 後隨= 常量表達式 ,則其值為該常量表達式的值。若枚舉常量 沒有後隨=常量表達式  ,則其值是比同一枚舉中前一枚舉項的值大一的值。首個枚舉項(若它不用 = 常量表達式 )的值是零。

enum Foo { A, B, C = 10, D, E = 1, F, G = F + C};
// A=0, B=1, C=10, D=11, E=1, F=2, G=12

若使用標識符 ,則其自身成為標籤命名空間中枚舉類型的名稱,且需要使用關鍵詞 enum (除非 typedef 到通常命名空間)。

enum color { RED, GREEN, BLUE };
enum color r = RED; // OK
// color x = GREEN; // 错误: color 不在通常命名空间中
typedef enum color color_t;
color_t x = GREEN; // OK

每個無固定底層類型的(C23 起)枚舉類型與如下之一兼容char、有符號整數類型或無符號整數類型(不包括 bool 和位精確整數類型)(C23 起)。對於任何枚舉類型,哪一個類型是兼容的是實現定義的,但無論是那種類型,都必須有足以表示該枚舉中所有枚舉項的值。對於所有具有固定底層類型的枚舉,枚舉的類型均與枚舉的底層類型兼容。(C23 起)

沒有固定底層類型的枚舉類型,在其完成處枚舉成員的類型為:

  • 如果枚舉的所有值均可表示為一個 int 則為 int;否則,
  • 所枚舉的類型。
(C23 起)
所有枚舉均有底層類型。可以通過用 enum-類型說明符 顯式指定底層類型,並作為其固定底層類型。如果未顯示指定,則其底層類型為枚舉的兼容類型,它為有符號或無符號的整數類型或 char (C23 起)

枚舉類型是整數類型,從而可以用於任何其他整數類型能用之處,包括隱式轉換算術運算符

enum { ONE = 1, TWO } e;
long n = ONE; // 提升
double d = ONE; // 转换
e = 1.2; // 转换,e 现在是 ONE
e = e + 1; // e 现在是 TWO

註解

不同於 structunion , C 中沒有 enum 的前置聲明:

enum Color; // 错误:C 中无 enum 的前置声明
enum Color { RED, GREEN, BLUE };

枚舉允許以比 #define 更加便利和結構化的方式生成具名常量;它們可見於調試器,遵循作用域規則,並且參與類型系統。

#define TEN 10
struct S { int x : TEN; }; // OK

enum { TEN = 10 };
struct S { int x : TEN; }; // 也 OK

自 C23 起也可用 constexpr 來達成相同目的:

constexpr int TEN = 10;
struct S { int x : TEN; }; // 也 OK

另外,由於 C 中結構體聯合體不建立其作用域,可以在前者的成員說明中引入枚舉類型及其枚舉常量,而之後其作用域與前者相同。

struct Element
{
    int z;
    enum State { SOLID, LIQUID, GAS, PLASMA } state;
} oxygen = { 8, GAS };
// 类型 enum State 与其枚举常量于此保持可见,例如
void foo(void) {
    enum State e = LIQUID; // OK
    printf("%d %d %d ", e, oxygen.state, PLASMA); // 打印 1 2 3
}

示例

#include <stdio.h>

int main(void)
{
    enum TV { FOX = 11, CNN = 25, ESPN = 15, HBO = 22, MAX = 30, NBC = 32 };

    printf("List of cable stations:\n");
    printf(" FOX: \t%2d\n", FOX);
    printf(" HBO: \t%2d\n", HBO);
    printf(" MAX: \t%2d\n", MAX);
}

輸出:

List of cable stations:
  FOX:   11
  HBO:   22
  MAX:   30

引用

  • C23 標準(ISO/IEC 9899:2024):
  • 6.2.5/21 Types (第 39 頁)
  • 6.7.2.2 Enumeration specifiers (第 107-112 頁)
  • C17 標準(ISO/IEC 9899:2018):
  • 6.2.5/16 Types (第 32 頁)
  • 6.7.2.2 Enumeration specifiers (第 84-85 頁)
  • C11 標準(ISO/IEC 9899:2011):
  • 6.2.5/16 Types (第 41 頁)
  • 6.7.2.2 Enumeration specifiers (第 117-118 頁)
  • C99 標準(ISO/IEC 9899:1999):
  • 6.2.5/16 Types (第 35 頁)
  • 6.7.2.2 Enumeration specifiers (第 105-106 頁)
  • C89/C90 標準(ISO/IEC 9899:1990):
  • 3.1.2.5 Types
  • 3.5.2.2 Enumeration specifiers

關鍵詞

enum

參閱

枚舉聲明C++ 文檔