自定义类型之联合体、枚举
自定义类型之联合体、枚举
- 1、联合体
- 1.1、联合体的声明
- 1.2、联合体的特点
- 1.3、联合体的大小计算
- 1.4、联合体的应用
- 1.4.1、例1
- 1.4.2、例2
- 2、枚举
- 2.1、枚举的声明
- 2.2、使用
- 2.3、枚举的优点
1、联合体
联合体,也叫共用体,与结构体类似,也是多个变量的集合。这些变量可以是不同类型的。
1.1、联合体的声明
union UN
{char c;int i;
};#include<stdio.h>int main()
{printf("%zu\n", sizeof(union UN));return 0;
}
上面代码打印的结果,也就是上面代码中的联合体类型,其大小是多少个字节?
在vs 2022中,答案是4。为什么是4呢?
这时,我们就要来了解一下,联合体的特点了。
1.2、联合体的特点
- 编译器只给最大的成员变量,分配足够的内存,也就是说,联合体的所有成员变量共用一个内存。
- 给其中一个成员赋值,其他成员可能跟着变化。
举一个例子,我们声明一个联合体变量类型,并创建变量,然后取出每个成员变量的地址,和该变量的地址:
union Un
{char c;int i;double d;
}u;#include<stdio.h>int main()
{printf("%p\n", &u.c);printf("%p\n", &u.i);printf("%p\n", &u.d);printf("%p\n", &u);return 0;
}
在vs 2022中,四个地址都是一样的,侧面印证了联合体各个成员变量共用一块内存空间。
再举一个例子,我们给联合体的其中一个成员变量赋值,观察另一个成员变量的变化:
union UN
{char c;int i;
};#include<stdio.h>int main()
{union UN u = { 0 };u.i = 0x11223344;printf("%x\n", u.i);u.c = 0x55;printf("%x\n", u.i);return 0;
}
(vs 2022环境为小端)低地址的第一个字节位置上,44被改为了55。
思索片刻,我们就可以画出这样一副示意图:
1.3、联合体的大小计算
规则:
- 联合体的大小,至少是最大成员变量的大小。
- 当最大成员变量的大小,不是最大对齐数的整数倍,就对齐到最近的最大对齐数整数倍处。
#include<stdio.h>union un1 //例1
{char c[5];//按元素int i;
};union un2 //例2
{short c[7];int i;
};union un3 //例3
{ //有嵌套,参照结构体的内存对齐 char c;union un2 u1;int i;
};#include<stdio.h>int main()
{printf("%zu\n", sizeof(union un1));//8printf("%zu\n", sizeof(union un2));//16printf("%zu\n", sizeof(union un3));//16return 0;
}
再回到1.1,不难得出,答案是4。
如果1.1中,联合体类型换成结构体类型,大小就是8字节,就要浪费3字节;而联合体就不会浪费。
1.4、联合体的应用
1.4.1、例1
假如我们要做一个线上礼品兑换单,商品名和包含的信息如下:
- 图书:库存量、价格、商品类型(可能存在编码)、书名、作者、页数。
- 杯子:库存量、价格、商品类型、设计(可能存在款式对应的编码)。
- 衬衫:库存量、价格、商品类型、设计、可选颜色(可能存在颜色对应的编码)、可选尺寸。
不假思索,我们可能直接就写出了这样一份代码:
struct goods
{//共有属性int num;//库存量int prize;//价格int int_item;//商品类型//特有属性char book_name[30];//书名char writer[30];//作者int page;//页数int int_design;//设计int int_color;//颜色int size;//可选尺寸
};
这样写,确实简单明了,但是也占用了比较多的内存,有没有什么好的方法?
我们可以看到,商品的信息包含共有的,和特有的。共有的信息是常用的。那么我们可以将共有的信息拎出来,而将特有的信息按商品类别分别整合,再放入一个联合体中:
struct goods
{//共有属性int num;//库存量int prize;//价格int int_item;//商品类型union cate//category{struct book{char book_name[30];//书名char writer[30];//作者int page;//页数};struct cup{int int_cup_design;//设计};struct shirt{int int_shirt_design;//设计int int_color;//颜色int size;//可选尺寸};};
};
这样,就可以节省一定的空间。
1.4.2、例2
这里我们利用联合体来判断环境的大小端类型。
我们已经学习了一个方法,那就是,定义一个整型变量(4字节),再赋值1,此时内存中就有01 00 00 00(小端)和00 00 00 01(大端)两种存法。取出该变量的地址,强转为字符类型并取出,再判断是否为1。
简单图示:
是不是很像int
类型的数据与char
类型的数据共用内存?
灵感来了:我们可以创建联合体,只有int
和char
类型。先赋上空值,然后向int
类型变量赋值1,再返回char
类型变量的值,并判断:
#include<stdio.h>union un
{int i;char c;
};int check_sys()
{union un u1 = { 0 };u1.i = 1; return u1.c;
}int main()
{int ret = check_sys();if (1 == ret)printf("小端\n");else if (0 == ret)printf("大端\n");return 0;
}
2、枚举
枚举,顾名思义,就是一一列举。
2.1、枚举的声明
enum Day//星期
{zero,//0Monday,//1Tuesday,//2Wenesday,Thursday,Friday,Saturday,Sunday
};enum Sex//性别
{Female,Male,Secret
};enum color//颜色
{red,green,blue
};
enum Day
enum Sex
enum color
都是枚举类型,其中的值都是枚举常量。
枚举常量:
- 是常量,从0开始向下递增,每次加1。
- 也可以在声明内赋值,但是下一个未赋值的常量,就是上一个加1。
2.2、使用
可以给枚举变量赋值枚举常量:
enum color//颜色
{red,green,blue
};enum color c1 = blue;
但是,C语言中,可以给枚举变量赋值整数;而C++中不行。
2.3、枚举的优点
- 增加代码的可读性、可维护性。
- 相比
#define
,枚举有类型检查,更严谨。 - 便于调试,预处理阶段会删除
#define
定义的符号。 - 使用方便,一次可以定义多个常量。
- 遵循作用域规则,在函数内声明,就只能在函数内使用。
比如可读性,在前面的计算器的简单实现中,我们用数字代表要选择则的操作。这时我们就可以使用枚举,定义对应整数的枚举常量,而枚举常量又可以被命名为对应操作(加、减、乘、除)的名字。这样就增加了代码的可读性。