C 語言程式設計教學:列舉 (Enumeration)

PUBLISHED ON AUG 26, 2018 — PROGRAMMING

列舉 (enum 或 enumeration) 是另一種複合型別,主要是用在僅有少數值的型別,像是一星期內的日期 (day of week) 或是一年內的月份等。透過列舉,我們可以在程式中定義幾個獨一無二的符號 (symbol),且該符號享有型別安全。

宣告列舉

使用 enum 保留字可以宣告列舉,如下例:

enum direction {
    North,
    South,
    East,
    West
};

int main(void) {
    enum direction dest = East;
    
    return 0;
}

列舉同樣可用 typedef 簡化型別名稱,如下例:

// Foreward declaration.
typedef enum direction Direction;

enum direction {
    North,
    South,
    East,
    West
};

int main(void) {
    Direction dest = East;
    
    return 0;
}

由於 C 語言的列舉本身沒有前綴,可以自行加入前綴,如下例:

typedef enum direction Direction;

// Enum with prefix.
enum direction {
    Direction_North,
    Direction_South,
    Direction_East,
    Direction_West
};

int main(void) {
    Direction dest = Direction_East;
    
    return 0;
}

雖然前綴不是強制規定,有些程式設計者偏好此種風格,以減少命名空間衝突。

有些程式設計者會將列舉用全大寫來表示:

enum direction {
    NORTH,
    SOUTH,
    EAST,
    WEST
};

這種觀點將列舉視為一種常數,這些不是硬性規定,而屬個人風格,讀者可自由選用。

列舉 vs. 常數

我們若不使用列舉,也可以用常數 (constant) 替代,如下例:

typedef unsigned short Direction;

// Compile time constants.
#define NORTH 1
#define SOUTH 2
#define EAST  3
#define WESt  4

int main(void) {
    Direction dest = EAST;
    
    return 0;
}

在這裡我們用到基本的前置處理器語法,讀者不用太在意其使用細節,將其視為編譯期的常數即可。

常數和列舉的主要差別在於型別安全,前者沒有型別安全,如下例:

typedef unsigned short Direction;

#define NORTH 1
#define SOUTH 2
#define EAST  3
#define WESt  4

int main(void) {
    // Wrongly correct.
    Direction dest = 6;
    
    return 0;
}

但使用列舉時,就會在編譯程式時引發錯誤:

typedef enum direction Direction;

enum direction {
    North,
    South,
    East,
    West
};

int main(void) {
    // Error!
    Direction dest = South_West;
    
    return 0;
}

列舉是 ANSI C 就有的特性,如果想在程式中使用列舉,不需要刻意使用常數來模擬。

讀取列舉的數字

一般來說,我們使用列舉時,將其視為一種符號,不會在意其內部的數值;但必要時也可指定列舉的值,如下例:

#include <assert.h>

enum mode {
    READ = 4,
    WRITE = 2,
    EXEC = 1
};

int main(void) {
    assert(READ ^ WRITE == 6);
    
    return 0;
}

comments powered by Disqus