You are on page 1of 9

枚举

枚举变量的本质到底是什么
共用体
共用体的应用

枚举
在学习枚举之前,我们看一下编程中会遇到的实际问题。  
比如,我们如何表示和记录“星期几”?  
一般而言,我们会自我约定,用不同的数字,来表示不同的日期。

1 #include <stdio.h>
2
3
4 int main(int argc, char* argv[])
5 {
6     int iWeekDay = ‐1;
7     /*
8     0 ‐ 星期1
9     1 ‐ 星期2
10     2 ‐ 星期3
11     ……
12     */
13
14     iWeekDay = 2; //赋值今天是星期3
15
16     switch (iWeekDay)
17     {
18     case 0:
19         printf("今天是星期1\r\n");
20         break;
21     case 1:
22         printf("今天是星期2\r\n");
23         break;
24     case 2:
25         printf("今天是星期3\r\n");
26         break;
27     case 3:
28         printf("今天是星期4\r\n");
29         break;
30     case 4:
31         printf("今天是星期5\r\n");
32         break;
33     case 5:
34         printf("今天是星期6\r\n");
35         break;
36     case 6:
37         printf("今天是星期7\r\n");
38         break;
39     }
40
41
42     return 0;
43 }

通过以上代码的示例,我们知道,我们常常采用int类型的变量,来存储“标志”。根据
约定,使用不同的数字,表示不同的状态。  
但是,这可能会导致误输入的问题,比如:

1 iWeekDay = 70; 

根据我们的约定,70不在约定范围之内,逻辑上是错误的。但是,从C语言的语法角
度而言,并没有错。  
看了以上的矛盾后,就期待有一种可以限制变量范围的语法,C语言为了解决这个矛
盾,发明了枚举。

枚举语法  
枚举本身也不是基本数据类型,类似于struct,我们是先需要定义枚举类型,再用我们
自定义的类型,定义变量。  
枚举的关键字是enum,比如:

1 enum ENUM_WEEKDAY
2 {
3     Monday,
4     Tuesday,
5     Wendsday,
6     Thrusday,
7     Friday,
8     //...
9 };

接着,我们可以使用枚举类型,定义枚举变量:

1 enum ENUM_WEEKDAY myEnum;

枚举变量的特点在于:其赋值范围,被枚举类型中声明的状态所限制。  
以下合法:

1     myEnum = Monday;
2     myEnum = Wendsday;

以下非法(70不是我们枚举类型的状态):

1     myEnum = 70;

不仅如此,枚举变量是可以用于switch语句:

1 #include <stdio.h>
2
3 enum ENUM_WEEKDAY
4 {
5     Monday,
6     Tuesday,
7     Wendsday,
8     Thrusday,
9     Friday,
10     //...
11 };
12 int main(int argc, char* argv[])
13 {
14     enum ENUM_WEEKDAY myEnum;
15
16     myEnum = Wendsday;
17
18     switch (myEnum)
19     {
20     case Monday:
21         printf("星期1\r\n");
22         break;
23     case Tuesday:
24         printf("星期2\r\n");
25         break;
26     case Wendsday:
27         printf("星期3\r\n");
28         break;
29     case Thrusday:
30         printf("星期4\r\n");
31         break;
32     case Friday:
33         printf("星期5\r\n");
34         break;
35     default:
36         break;
37     }
38
39
40     return 0;
41 }

使用枚举,代码更规范,可读性更强。

枚举变量的本质到底是什么
结合我们之前学习过的switch语法。我们可以猜测出,枚举变量要么是整型,要么可
以转为整型。  
我们通过调试来取证以下:  
通过实践,我们可以发现规律,其实枚举本质上就是整型变量,其所为的状态,其实
是从0开始的编号数字常量。

1 enum ENUM_WEEKDAY
2 {
3     Monday, // 0
4     Tuesday,  //1
5     Wendsday, //2
6     Thrusday, //3
7     Friday, //4
8     //...
9 };

实际上,枚举在内存中,与int类型是没有区别的,它的特殊之处是编译器会进行编译
时的检查。  
我们理解以上内容之后,我们可以理解:

1 enum ENUM_WEEKDAY
2 {
3     Monday = 3, 
4     Tuesday,  
5     Wendsday, 
6     Thrusday, 
7     Friday, 
8     //...
9 };

用以上的语法,来决定状态对应的数字。

共用体
共用体与struct、enum都属于非基本数据类型,换言之,我们需要先根据关键字,定
义自己的共用体类型。再利用定义的共用体类型,定义共用体变量。  
我们通过生活中的一个例子,来抽象出共用体发明的初衷。  
某个小区,有一个黑板,这个黑板常常用来发布消息。  
发布的消息类型有以下几种:

物业的费用使用情况,double

人口统计:int
宣传标语:char[12]

用现有的语法,我们如何定义一个变量,可以表示这多种类型呢?  
我们可以使用struct:

1 #include <stdio.h>
2 #include <string.h>
3
4 struct tagBlackBoard
5 {
6     double dFee;
7     int iPopulation;
8     char szMsg[12];
9 };
10
11 int main(int argc, char* argv[])
12 {
13     tagBlackBoard blackBoard;
14     //通告1
15     blackBoard.dFee = 3000.5;
16
17     //通告2
18     blackBoard.iPopulation = 5000;
19
20     //通过3
21     strcpy(blackBoard.szMsg, "Welcome!");
22     return 0;
23 }

以上的代码虽然可以完成任务,但是却存在着浪费的情况:不同类型的通告,是不会
同时出现的。但是我们使用struct类型,却会为所有成员,都同时分配独立的内存空
间。

为了不浪费,C语言中发明了共用体(联合体)语法,共用体的关键字是union。  
其语法与struct类似的:

1 #include <stdio.h>
2 #include <string.h>
3
4 union tagBlackBoard
5 {
6     double dFee;
7     int iPopulation;
8     char szMsg[12];
9 };
10
11 int main(int argc, char* argv[])
12 {
13     tagBlackBoard blackBoard;
14     //通告1
15     blackBoard.dFee = 3000.5;
16     printf("费用:%f\r\n", blackBoard.dFee);
17
18     //通告2
19     blackBoard.iPopulation = 5000;
20     printf("人口:%d\r\n", blackBoard.iPopulation);
21
22     //通过3
23     strcpy(blackBoard.szMsg, "Welcome!");
24     printf("标语:%s\r\n", blackBoard.szMsg);
25     return 0;
26 }

union和struct在使用上有一定相似之处(先定义类型,再定义变量,并且使用"."引用
成员)。  
但是,他们的内存结构,却有很大的区别:

1 union tagBlackBoard
2 {
3     double dFee;
4     int iPopulation;
5     char szMsg[12];
6     double dFee2;
7 };
8
9 int main(int argc, char* argv[])
10 {
11     printf("%d\r\n", sizeof(tagBlackBoard));
12     return 0;
13 }

可以发现,整个共用体的大小,并不是所有成员大小的和,这是因为:  
共用体的所有成员,共享一块内存。  
共用体变量的大小,由最大的成员决定(同时考虑对齐)。  
共用体的好处,是可以使用同一块内存空间,表示不同类型的变量,在某些场景中,
可以节约资源。

共用体的应用
编码转化  
之前我们学习了浮点编码的知识。请大家尝试通过编程的方法解决一下问题:

1 float fValue1 = 3.14f;

如何输出fValue1的十六进制编码值。  
学习了共用体之后:
1 #include <stdio.h>
2 #include <string.h>
3
4 union uFlotValue
5 {
6     float fValue;
7     unsigned char ucData[4];
8 };
9
10 int main(int argc, char* argv[])
11 {
12     float fValue1 = 3.14f;
13
14     uFlotValue uObj;
15     uObj.fValue = fValue1;
16
17     for (size_t i = 0; i < 4; i++)
18     {
19         printf("%02X ", uObj.ucData[i]);
20     }
21     return 0;
22 }

IP转换问题  
大家上网都了解过IP地址,比如IPV4的地址,大家可能看到的是:192.168.0.1。  
是4个0~255范围内的数字,然后通过点分割。  
实际上IPV4地址的本质,就是int类型的整数。  
所谓的4个数字,其实就是以1字节为单位,转为十进制表示的数字而已。

You might also like