Professional Documents
Culture Documents
最强C语言 11 枚举、共用体.md
最强C语言 11 枚举、共用体.md
最强C语言 11 枚举、共用体.md
枚举变量的本质到底是什么
共用体
共用体的应用
枚举
在学习枚举之前,我们看一下编程中会遇到的实际问题。
比如,我们如何表示和记录“星期几”?
一般而言,我们会自我约定,用不同的数字,来表示不同的日期。
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字节为单位,转为十进制表示的数字而已。