16.5 枚举(C语言)

目录

16.5.1 枚举标记和类型名

16.5.2 枚举作为整数

16.5.3 用枚举声明标记字段


C语言为具有可能值较少的变量提供了一种专用类型。枚举类型 是一种值由程序员列出(枚举)的类型,而且程序员必须为每个值命名。我们把这些名字称为 枚举常量

/* 扑克牌花色成为整数的别名 */
enum {CLUBS, DIAMONDS, HEARTS, SPADES} s1, s2;

如果枚举声明在函数体内,那么它的常量对外部函数来说是不可见的。

16.5.1 枚举标记和类型名

命名枚举的两种方法:

  1. 通过声明标记的方法
  2. 使用 typedef 来创建独一无二的类型名

枚举标记类似于结构和联合的标记。

enum [枚举名] {枚举元素列表};

/* 声明了一个枚举类型enum Suit */
enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES};

枚举变量 s1 和 s2 可以按照下列方法来声明:

enum Suit s1, s2;

枚举变量和其它数值型量不同,它们的取值只限于花括号中指定的值之一。因此,s1 和 s2 的值只能是 CLUBS, DIAMONDS, HEARTS, SPADES 之一。

也可以不声明有名字的枚举类型,而直接定义枚举变量,例如:

enum {CLUBS, DIAMONDS, HEARTS, SPADES} s1, s2;

还可以用 typedef 把 Suit 定义为类型名:

typedef enum {CLUBS, DIAMONDS, HEARTS, SPADES} Suit;

在 C89 中,利用 typedef 来命名枚举是创建布尔类型的一种非常好的方法:

typedef enum {FALSE, TRUE} Bool;

16.5.2 枚举作为整数

在系统内部,C语言会把枚举变量和枚举常量作为整数来处理。默认情况下,编译器会把整数 0, 1, 2, ... 赋给特定枚举中的常量。例如,在枚举 suit 的例子中,CLUBS、DIAMONDS、HEARTS 和 SPADES 分别表示 0、1、2 和 3。

我们可以为枚举常量自由选择不同的值:

enum suit {CLUBS = 1, DIAMONDS = 2, HEARTS = 3, SPADES = 4};

枚举常量的值可以是任意整数,也可以不用按照特定的顺序列出:

enum suit {CLUBS = 20, DIAMONDS = 10, HEARTS = 15, SPADES = 25};

当没有为枚举常量指定值时,它的值比前一个常量的值大 1 。并且在默认情况下,第一个枚举常量的值默认为 0 。

/* CLUBS = 0, DIAMONDS = 10, HEARTS = 11, SPADES = 25 */
enum suit {CLUBS, DIAMONDS = 10, HEARTS, SPADES = 25};

枚举的值只不过是一些稀疏分布的整数,所以C语言允许把它们与普通整数进行混合:

int i;
enum {CLUBS, DIAMONDS, HEARTS, SPADES} s;
i = DIAMONDS;    /* i is now 1            */
s = 0;           /* s is now 0 (CLUBS)    */
s++;             /* s is now 1 (DIAMONDS) */
i = s + 2;       /* i is now 3            */

注意:虽然把枚举的值作为整数使用非常方便,但是把整数用作枚举的值是非常危险的。例如,我们可能会不小心把 4 存储到 s 中,而 4 不能跟任何花色相对应。

16.5.3 用枚举声明标记字段

所遇问题:

定义一种联合类型,它所包含的成员分别表示要存储在数组中的不同数据类型:

typedef union {
    int i;
    double d;
} Number; /* i 和 d 是联合 Number 的成员 */

接下来,创建一个数组,使数组的元素是 Number 类型的值:

Number number_array[1000];

可以在数组 number_array 中存储 int 和 double 的混合值:

number_array[0].i = 5;
number_array[1].d = 8.395;

假设编写了一个函数,用来显示当前存储在联合 Number 中的值。这个函数可能有下列框架:

void print_number(Number n) {
    if (n 包含一个整数)
        printf("%d", n.i);
    else
        printf("%g", n.d);
}

为了帮助函数 print_number 确定 n  包含的是整数还是浮点数,我们可以把联合嵌入到一个结构体中,并且此结构体还含有另一个成员:标记字段,它是用来提示当前存储在联合中的内容的。

下面把 Number 类型转换成具有嵌入联合的结构体类型:

#define INT_KIND 0
#define DOUBLE_KIND 1

typedef struct {
    int kind;    /* tag field */
    union {
        int i;
        double d;
    } u;
} Number;

每次给 u 的成员赋值时改变 kind 的值,从而提示修改的是 u 的哪个成员:

Number n;
n.kind = INT_KIND;
n.u.i = 82;

问题得到初步解决:

void print_number(Number n) {
    if (n.kind == INT_KIND)
        printf("%d", n.i);
    else
        printf("%g", n.d);
}

 用枚举来解决上述问题是非常合适的:

typedef struct {
    enum {INT_KIND, DOUBLE_KIND} kind;    /* tag field */
    union {
        int i;
        double d;
    } u;
} Number;

不仅避免了使用宏定义——此时 INT_KIND 和 DOUBLE_KIND 是枚举常量——还阐明了 kind 的含义。现在 kind 显然只有两种可能的值:INT_KIND 和 DOUBLE_KIND。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值