第十八章、枚举

无论任何的数据,在计算机内都要用数字来表示。比如在表示性别时,我们用 1 表示男性,用 0 表示女性;表示成功还是失败时我们用 0 表示成功,-1 表示失败等。当我们打开之前写的程序时我们可能会发现我们写过如下的代码:

result = 0;

请问这个 0 是表示成功还是失败呢?当初我们是怎么定义这个 0 的含义呢?

为了提高代码的可读性,提高编写代码的效率。我们通常用标识符来表示数值,常用的方法有两种:

  1. 使用宏定义代替值,如: #define SUCCESS (1)#define ERROR (0)
  2. 使用枚举类型,如: enum {ERROR = 0, SUCCESS = 1};

当我们使用宏定义时。我们上述代码可以写成:

#define SUCCESS  (1)
#define ERROR    (0)

result = ERROR;

这样程序的可读性就好很多。

当让我们可以使用枚举类型,上面的代码依旧可以写成

enum {ERROR = 0, SUCCESS = 1};

result = ERROR;

以上两种写法都增强了代码的可读性。其中使用宏的方法是预处理阶段进行源码级提换,使用枚举则是在编译阶段进行数据处理。

这一章我们来学习 枚举类型。

1. 枚举

枚举(Enumeration) 是 C 语言中的一种基本数据类型,它主要用于定义一组标识符来代表整数常量。让代码更具可读性和可维护性。

语法:

enum [枚举类型名] {
    枚举常量名1[ = 整数常量表达式1],
    枚举常量名2[ = 整数常量表达式2],
    ...
} [变量名 [= 整数表达式]];

说明:

  1. 枚举有自己的类型,类型名为 enum 枚举类型名
  2. 枚举类型名 必须是标识符,可以省略不写,省略不写则只能在声明时直接定义变量,后续不能使用类型名定义该类型的变量。
  3. 枚举常量 必须是标识符,它代表一个整数常量值,只能取值不能赋值。
  4. 枚举常量 如果没有给出初始值,则它的值是上一个 枚举常量 的值加 1。
  5. 第一个 枚举常量 如果没有给出初始值,则它的值是 0。
  6. enum [枚举类型名] {...} 部分是类型声明,后面可以定义该类型的变量,也可以直接用分号(;)结束声明。

例如:

// 声明一个枚举类型 WeekDay 表示一周中的星期几。
enum WeekDay {
    Mon = 1,  // Mon 值为1
    Tue,  // Tue 值为 2
    Wed,  // Wed 值为 3
    Tru,  // Tru 值为 4
    Fri,  // Fri 值为 5
    Sat,  // Sat 值为 6
    Sun  // Sun 值为 7
};

// 声明一个枚举类型 ReturnState,同时定义一个变量 result。
enum ReturnState{
    DISABLE,  // ERROR 值为 0
    ENABLE = 2,  // ENABLE 值为 2
    OTHER_RESULT = -1  // OTHER_RESULT 值为 -1
} result;

// 声明两个枚举类型的常量值 ERROE 和 SUCCESS。
enum {
    ERROR,  // ERROR 值为 0
    SUCCESS = !ERROR,  // SUCCESS 值为 1
};

// 声明两个枚举类型的常量值 RESET 和 SET,同时定义一个变量 x, y;
enum {
    RESET = -1,  // RESET 值为 -1
    SET  // SET 值为 -1
} x, y;

使用枚举类型声明变量的语法:

enum 枚举类型名 变量名1 [= 整数表达式1][, 变量名1 [= 整数表达式1]]];

说明:

如果一个枚举类型在声明时没有给出类型名。则可以定义整数类型变量来保存其值。

示例

// filename: enumeration.c
#include <stdio.h>

// 声明一个枚举类型 WeekDay 表示一周中的星期几。
enum WeekDay {
    Mon = 1,  // Mon 值为1
    Tue,  // Tue 值为 2
    Wed,  // Wed 值为 3
    Tru,  // Tru 值为 4
    Fri,  // Fri 值为 5
    Sat,  // Sat 值为 6
    Sun  // Sun 值为 7
};

// 声明一个枚举类型 ReturnState,同时定义一个变量 result。
enum ReturnState{
    DISABLE,  // ERROR 值为 0
    ENABLE = 2,  // ENABLE 值为 2
    OTHER_RESULT = -1  // OTHER_RESULT 值为 -1
} result;

// 声明两个枚举类型的常量值 ERROE 和 SUCCESS。
enum {
    ERROR,  // ERROR 值为 0
    SUCCESS = !ERROR,  // SUCCESS 值为 1
};


// 声明两个枚举类型的常量值 RESET 和 SET,同时定义一个变量 x, y;
enum {
    RESET = 0,
    SET = !RESET
} x, y;

int main(int argc, char * argv[]) {
    enum WeekDay theday;
    int ret = ERROR;
    if (ret != SUCCESS) {
        printf("result: %d\n", result);
    }
    x = SET;
    printf("x: %d\n", SET);
    printf("sizeof(x): %ld\n", sizeof(x));
    printf("sizeof(SET): %ld\n", sizeof(SET));

    for (theday = Mon; theday <= Sun; theday++) {
        printf("theday: %d\n", theday);
    }

    return 0;
}

编译和运行结果如下:

result: 0
x: 1
sizeof(x): 4
sizeof(SET): 4
theday: 1
theday: 2
theday: 3
theday: 4
theday: 5
theday: 6
theday: 7

从容上述运行结果可知,枚举类型的枚举常量可以当做整数常量来使用。

枚举类型的变量 和 枚举常量 的类型在不同的编译器下使用的内存长度是不一致的。大多数编译器将枚举类型看做是整数(四个字节),但也会有编译器将枚举类型的变量用一个字节保存。具体要看编译器和枚举常量的值来决定。

练习:

声明枚举类型 Season 来表示季节中的 四个常量值(用标识符表示)。然后定义变量保存其中的某一个值。