前言
自定义类型有三种:结构体,联合体以及枚举。在上一篇博客中我们已经讲解了结构体,接下来我们将学习联合体和枚举。
联合体(Union)是一种特殊的数据结构,允许在同一内存位置存储不同的数据类型。与结构体不同,联合体的各个成员共享同一块内存空间,因此联合体的大小等于其最大成员的大小 (当最大成员大小等于最大对齐数的整数倍时) 。这意味着在联合体中只能存储一个成员的值,而不是多个成员的值。
//联合体示范
union MyUnion {
int i;
float f;
char c;
};
在这个示例中,MyUnion 是一个联合体,它可以存储一个整数 i、一个浮点数 f 或一个字符 c。这些成员共享同一块内存空间,因此在任何时候只能存储其中一个成员的值。
联合的成员是共用⼀块内存空间的,以下几个例子来证明:
//代码1
#include
//联合类型的声明
union Un{
char c;
int i;
};
int main(){
//联合变量的定义
union Un un = { 0 };
// 下⾯输出的结果是⼀样的吗?
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
printf("%p\n", &un);
return 0;
}
运行结果:
由此可见,无论是任何一个联合体成员,还是联合体本身,它们的地址是一样的
再来看联合体成员在内存中的数据:
//代码2
#include
//联合类型的声明
union Un{
char c;
int i;
};
int main(){
//联合变量的定义
union Un un = { 0 };
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
return 0;
}
结果如下:
当我们把16进制的11223344赋值给i,又把55赋值给c,后来我们想取出 i 时发现,其中一部分已经被c覆盖了。
当我们使用联合体时,可以看到,c和i是共用一个内存,且给un.c赋值时会覆盖掉一个字节的内容
有以下两个条件:
举例:
#include
union Un1{//Un1的大小大于或等于5(5个char>1个int),又Un1的大小应当是4的整数倍,所以Un1的大小是8
char c[5];//char大小为1,默认对齐数8,对齐数1
int i; //int大小为4,默认对齐数8,对齐数4
};
union Un2{//Un2的大小大于或等于14(7个short>1个int),又Un2的大小应当是4的整数倍,所以Un1的大小是16
short c[7];//short大小为2,默认对齐数8,对齐数2
int i; //int大小为4,默认对齐数8,对齐数4
};
int main(){
//下⾯输出的结果是什么?
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}
结果如下:
//结构体
struct S{
char c;
int i;
};
struct S s = {0};
//联合体
union Un{
char c;
int i;
};
union Un un = {0};
显而易见,联合体更加节省空间,但由于联合体的成员共用一个内存空间,所以联合体的使用是有限制的
例如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
struct gift_list{
int stock_number;//库存量
double price; //定价
int item_type;//商品类型
union {
struct{
char title[20];//书名
char author[20];//作者
int num_pages;//⻚数
}book;
struct{
char design[30];//设计
}mug;
struct{
char design[30];//设计
int colors;//颜⾊
int sizes;//尺⼨
}shirt;
}item;
};
因为每一种商品都有自己独特的属性,当我们描述一种商品时需要库存量、价格、商品类型以及仅描述该商品的特殊属性。这时联合体比结构体更加节省空间。因此使用哪一种自定义类型取决于描述的对象。
枚举类型(Enum)是一种用于定义命名整数常量的数据类型。 允许程序员为一组相关的整数值分配有意义的名称,以提高代码的可读性和可维护性。
enum 枚举名称 {
枚举值1,
枚举值2,
// 可以有更多的枚举值
};
举例,列举颜色:
#include
enum Color{//颜⾊
RED,
GREEN,
BLUE
};
int main() {
printf("%d %d %d",RED,GREEN,BLUE);
return 0;
}
#include
enum Color{//颜⾊
RED,
GREEN=5,
BLUE
};
int main() {
printf("%d %d %d",RED,GREEN,BLUE);
return 0;
}
枚举的优点:
enum Weekday {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
};
enum Weekday today = TUESDAY;
if (today == MONDAY) {
printf("今天是星期一\n");
} else if (today == TUESDAY) {
printf("今天是星期二\n");
}
switch (today) {
case MONDAY:
printf("今天是星期一\n");
break;
case TUESDAY:
printf("今天是星期二\n");
break;
// 其他星期几的情况
default:
printf("今天不是星期一或星期二\n");
break;
}
枚举的使用与#define定义常量类似,但枚举和#define定义的标识符⽐较枚举有类型检查,更加严谨。