枚举
引入
对于一周中的七天,为每个天数定义一个别名,在使用的时候用别名就知道是第几天。
对于上述问题,很容易就想到用宏定义来实现,如下:
#define Mon 1
#define Tue 2
#define Thu 3
#define Wed 4
#define Fri 5
#define Sat 6
#define Sun 7
但是宏名太多会导致代码比较松散,看起来总感觉不舒服,c语言提供了一种枚举类型(enum),能够列出所有可能取值,并给他们去取一个名字。
枚举的定义和格式
枚举定义的语法格式和结构体类似,区别只在于,每一个枚举元素后面都是逗号,最后一个枚举元素后面无符号,其他定义格式都和结构体差不多:
enum 枚举名
{
枚举元素1,
枚举元素2,
……
};
用枚举来实现上述问题。因为枚举类型里面,第一个元素默认值是0,后面的元素默认值依次+1,所以在这里把首元素的值改成1,那么该类型的元素取值依次是1-7,符合要求:
enum day
{
Mon=1,
Tue,
Thu,
Wed,
Fri,
Sat,
Sun
};
枚举元素的取值/枚举常量
运行下面一段代码,结果如下,不难发现,在定义枚举类型时,如果里面的枚举元素的值不作修改,那么就默认从0开始,依次加1,对应下方的运行结果就是:0-4。但是如果某一个枚举元素的值修改了,那么对这个枚举元素前面的枚举元素没有影响,比如Sat改成了10,但是对前面Mon到Fri的值无影响,只影响了后面的枚举元素的值,后面依然是依次+1。
#include<stdio.h>
enum Day
{
Mon,
Tue,
Wen,
Thu,
Fri,
Sat=10,
Sun
};
int main()
{
printf("%d\n", Mon);
printf("%d\n", Tue);
printf("%d\n", Wen);
printf("%d\n", Thu);
printf("%d\n", Fri);
printf("%d\n", Sat);
printf("%d\n", Sun);
return 0;
}
枚举元素又被称作枚举常量,既是常量,那么在使用的时候就无法修改 ,如下,依然是上面的枚举,但是我在使用的时候,想要改变其中Thu的值,这个时候它产生错误,并且提示“表达式必须是可修改的左值”,那么印证了Thu是不可修改的:
枚举的应用
枚举在switch语句里面应用较多,比如下方代码,用枚举元素red,green,blue来代替1、2、3:
#include <stdio.h>
#include <stdlib.h>
enum color
{
red=1,
green,
blue
};
int main()
{
enum color favorite_color;
/* 用户输入数字来选择颜色 */
printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): ");
scanf("%u", &favorite_color);
/* 输出结果 */
switch (favorite_color)
{
case red:
printf("你喜欢的颜色是红色");
break;
case green:
printf("你喜欢的颜色是绿色");
break;
case blue:
printf("你喜欢的颜色是蓝色");
break;
default:
printf("你没有选择你喜欢的颜色");
}
return 0;
}
此外,枚举可以用来判断机器是大端存储模式还是小端存储模式。比如下方代码,把1赋值给u.b,那么如果是大端存储,内存从低位到高位应该是 00 00 00 01,如果是小端存储,内存从低位到高位应该是 01 00 00 00。这个时候只看第一个字节的内容就可以,而char类型的数据正好是只存一个字节的空间,所以用联合里的a成员来读取数据,判断大小端。如下,VS2019是小端存储,正确。
#include<stdio.h>
//在判断机器大小端方面的应用
union
{
char a;
int b;
}u; //匿名联合
int main()
{
u.b = 1;
if (u.a == 0)
printf("大端!\n");
else
printf("小端!\n");
return 0;
}
联合(共用体)
联合也是一种特殊的自定义类型,其定义格式和struct类似,只不过最开始的sturtc 改成了union 。这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
特征
联合,又被称作共用体,是因为其所有成员共同使用一块空间。通过以下的代码不难看出。并且这块空间的大小,是联合的所有成员里面,最大的数据类型的大小(联合也要对齐)。
#include<stdio.h>
//所有成员共用一块内存
union un
{
double b;
int a;
};
int main()
{
union un ab = {128};
printf("%p\n",&ab.a);
printf("%p\n", &ab.b);
}
初始化
《C和指针》关于“联合”一章中提到“联合变量可以被初始化,但这个初始值必须是联合第1个成员的类型”。
比如下方的代码,运行结果如下,不难发现,初始化的时候,128是初始化的ab.a而不是ab.b,至于为什么ab.b打印出来是0.000000,也不难理解,由于是初始化的ab.a,所以按照整形的存储规则来,VS2019下是小端存储模式,此时用浮点数的方式读取这个数据时,浮点数存储有效数字的区域都是0,所以打印ab.b会是0.000000。(关于整形和浮点型数据存储规则,可以看(80条消息) c语言中数据的存储_Austerlitzl的博客-CSDN博客)
#include<stdio.h>
//所有成员共用一块内存
union un
{
int a;
double b;
};
int main()
{
union un ab = {128};
printf("%d\n", ab.a);
printf("%f\n", ab.b);
printf("%d\n",sizeof(union un));
}
我们将位置互换一下,可以发现正合我们的预期,这次的初始值是ab.b的类型,而不是ab.a的类型:
#include<stdio.h>
//所有成员共用一块内存
union un
{
double b;
int a;
};
int main()
{
union un ab = {128};
printf("%f\n", ab.b);
printf("%d\n", ab.a);
}
对齐
和结构体的内存对齐一样,联合也要对齐。如下,联合test里面,第一个成员是一个数组,占14个字节大小,第二个成员是int类型变量,占4个字节大小。同时,第一个成员对齐数是2,第二个成员对齐数是4,所以test对齐数是4,最终占16个字节。运行截图如下。
#include<stdio.h>
union test
{
short a[7];
int b;
};
int main()
{
printf("%d \n", sizeof(union test));
return 0;
}
关于枚举和联合的内容就介绍到这里!!!喜欢的话请一键三连哦!