| 目录 |

22 枚举类型:enum

C 还为我们提供了另一种用名字表示整数常量的方式:enum。

例如:

enum {
  ONE=1,
  TWO=2
};

printf("%d %d", ONE, TWO);  // 1 2

在某些方面,它可能比使用 #define 更好——或者只是有所不同。主要区别如下:

由于它们属于整数类型,所以凡是整数能用的地方它们都能用,包括数组维度和 case 语句。

我们再来深入剖析一下。

22.1 enum 的行为

22.1.1 编号

除非你手动改写,否则 enum 会自动编号。

默认情况下,它们从 0 开始,并由此自动递增:

enum {
    SHEEP,  // 值为 0
    WHEAT,  // 值为 1
    WOOD,   // 值为 2
    BRICK,  // 值为 3
    ORE     // 值为 4
};

printf("%d %d\n", SHEEP, BRICK);  // 0 3

也可以强制指定特定的整数值,就像前面看到的那样:

enum {
  X=2,
  Y=18,
  Z=-2
};

值重复也没问题:

enum {
  X=2,
  Y=2,
  Z=2
};

如果省略了值,编号就会从最后指定的那个值开始,沿正方向继续计数。例如:

enum {
  A,    // 0,默认起始值
  B,    // 1
  C=4,  // 4,手动设置
  D,    // 5
  E,    // 6
  F=3,  // 3,手动设置
  G,    // 4
  H     // 5
}

22.1.2 尾随逗号

如果你喜欢这种风格,这样写完全没问题:

enum {
  X=2,
  Y=18,
  Z=-2,   // <-- 尾随逗号
};

近几十年来的语言里,这种写法越来越流行,所以看到它你也许会高兴。

22.1.3 作用域

enum 的作用域符合你的预期:如果在文件作用域,整个文件都能看到它;如果在某个块内,它就是该块的局部。

把 enum 定义在头文件里非常常见,这样就可以在文件作用域中 #include 它。

22.1.4 风格

你可能已经注意到,习惯上会把 enum 的符号声明为大写(用下划线分隔)。

这并不是硬性要求,但确实是非常非常常见的惯用法。

22.2 你的 enum 是一种类型

关于 enum,有一点很重要:它是一种类型,就跟 struct 是一种类型一样。

你可以给它一个标签名,以便之后引用这个类型并声明该类型的变量。

既然 enum 是整数类型,那为什么不干脆用 int 呢?

在 C 中,最好的理由是代码清晰——它是一种漂亮、带类型的方式,能在代码中表达你的想法。C(与 C++ 不同)实际上并不强制某个 enum 的取值落在任何范围内。

我们来看一个例子,其中声明一个类型为 enum resource 的变量 r,它可以存放这些值:

// 具名枚举,类型为 "enum resource"

enum resource {
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
};

// 声明一个类型为 "enum resource" 的变量 "r"

enum resource r = BRICK;

if (r == BRICK) {
    printf("I'll trade you a brick for two sheep.\n");
}

当然,你也可以给它们加上 typedef,不过我个人不喜欢这么做。

typedef enum {
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
} RESOURCE;

RESOURCE r = BRICK;

另一种合法但少见的捷径,是在声明 enum 的同时声明变量:

// 声明一个枚举,以及几个该类型的已初始化变量:

enum {
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
} r = BRICK, s = WOOD;

你也可以给 enum 起个名字,以便之后使用,这多半就是你在大多数情况下想做的事:

// 声明一个枚举,以及几个该类型的已初始化变量:

enum resource {   // <-- 类型现在为 "enum resource"
    SHEEP,
    WHEAT,
    WOOD,
    BRICK,
    ORE
} r = BRICK, s = WOOD;

简而言之,enum 是写出漂亮、作用域清晰、带类型、整洁的代码的好办法。


| 目录 |