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