上文我们已经介绍过自定义类型之结构体,本文将继续介绍自定类型剩下的两种:枚举、联合。
本文涉及到的主要内容有:
● 枚举 :
a. 枚举类型的定义
b. 枚举的优点
c. 枚举的使用
● 联合 :
a. 联合类型的定义
b. 联合的特点
c. 联合大小的计算
枚举顾名思义就是一一列举。把可能的取值一一列举。
比如我们日常生活中出现的:
星期一到星期日;
某个高中生的考试科目;
1-12个月
这些内容都是有限且固定的,此时就可以使用枚举类型。
枚举类型的一般语法:
enum tag//枚举标签
{
member-list;//枚举成员变量
};
enum是枚举类型的关键字。
枚举示例:
enum Day//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜色
{
RED,
GREEN,
BLUE
};
//枚举使用示例:
int main()
{
enum Color c = BLUE;
return 0;
}
以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫枚举常量 。这里要和结构体做以区分,枚举内的枚举常量都是常量,是以后该枚举类型可能的取值,且在使用时不可以修改!而结构体内的结构体成员都是变量,是可以修改来描述复杂事物的。
注意枚举常量的分割是以“,”为结尾而非“;”,其中最后一个枚举变量结束没有符号。
这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
例如:
enum Color//颜色
{
RED,
GREEN,
BLUE,
YELLOW = 6,
WHITE,
BLACK
};
int main()
{
printf("%d\n", RED);
printf("%d\n", GREEN);
printf("%d\n", BLUE);
printf("%d\n", YELLOW);
printf("%d\n", WHITE);
printf("%d\n", BLACK);
return 0;
}
既然枚举类型都是常量,我们也可以使用#define
来定义常量,为何选择枚举呢?
枚举的优点:
下面举个例子来说明枚举的一个实际使用场景:
还记得我们之前编写过的“实现计算器”的代码吗?
在菜单选择栏,我们使用switch语句来判断进行何种运算,原来是这样写的:
switch (input)
{
case 1:
Add();
break;
case 2:
Sub();
break;
case 3:
Mul();
break;
case 4:
Div();
break;
case 0:
break;
}
这里case的值很难让我们和它所执行的内容对应起来,对于代码的阅读者也是不太友好。但是如果我们使用枚举类型来将这些数字定义成某些常量呢?
enum INPUT
{
ADD = 1,
SUB = 2,
MUL = 3,
DIV = 4
};
switch (input)
{
case ADD:
Add();
break;
case SUB:
Sub();
break;
.....
}
这样代码的可读性是不是更好了?当然,更多的优点需要慢慢感悟!
PS.枚举类型的大小是一个int的大小:4。因为一个枚举变量只能有一种可能的取值,就是某一个枚举常量。
联合也是一种特殊的自定义类型
这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
//计算联合变量的大小
printf("%d\n", sizeof(un));
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
但是联合体的大小是不是就是其成员变量中最大的那个变量的大小呢?答案是否定的,具体在2.3节讲述。
此处我们来看一个联合体的具体使用案例:
编写一个函数来判断机器的存储方式是大端还是小端
这道题我们之前已经实现过,当时是用了强制类型转换的思想来实现判断的,具体代码如下:
int sys_check()
{
int a = 1;//1的16进制存储: 00 00 00 01
if (*(char*)(&a) == 1)
{
return 1;//小端
}
else
{
return 0;//大端
}
}
为了更清楚弄明白,这里仔细分析一下:
int a = 1;
为例:如果是1,就是小端存储,如果是0,就是大端存储。union un
{
char c;
int i;
};
利用联合体实现判断机器大小端函数的代码:
int sys_check()
{
union un
{
char c;
int i;
}u;
u.i = 1;//1的16进制存储: 00 00 00 01
return u.c;//直接返回联合中c的内容,如果是小端就是1,大端就是0
}
union Un1
{
char c[5];//对齐数:1 占用:5
int i;//对齐数:4 占用:4
};
union Un2
{
short c[7];//对齐数:2 占用:14
int i;//对齐数:4 占用:4
};
int main()
{
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
}
分析:
Un1:
char类型数组c占据5个字节,int类型的i占据4个字节,所以至少占5个字节。但是要对齐,因为char的对齐数是1,int对齐数是4,所以Un1的最大对齐数是4,因此Un1的大小是4的倍数,而5之后的下一个4的倍数就是8.
因此Un1大小为8
Un2:
short类型数组c占据14个字节,int类型i 占据4个字节,因此该联合至少占有14个字节。但是要对齐,因为short类型对齐数为2,int类型对齐数为4,所以Un2的最大对齐数是4。14之后的4的整数倍是16。
因此Un2的大小为16