结构体一个萝卜一个坑,每个成员都占自己的地。可有些时候,数据彼此不会同时用到——这时候还让它们各占各的,就显得有点浪费啦。于是 C 语言给了我们两位会省钱的小伙伴:联合体和枚举。
联合体:大家共用同一块地
联合体(也叫共用体)由多个成员组成,但编译器只为最大的那个成员分配空间,所有成员共用同一块内存。给其中一个赋值,其他成员的值会跟着变。
union Un {
int i; // 4 字节
char c; // 1 字节
};
printf("%zu\n", sizeof(union Un)); // 4 —— 只留最大的那个
而且这三个「地址」是同一个:
printf("%p\n", &(un.i));
printf("%p\n", &(un.c)); // 和上面一样
printf("%p\n", &un); // 也是同一个
联合体大小怎么算
大小至少是最大成员的大小;若最大成员大小不是「最大对齐数」的整数倍,就要再加到对齐数的整数倍。
union Un1 { char c[5]; int i; }; // char[5]=5, 对齐到 4 的倍数 → 8
union Un2 { short c[7]; int i; }; // short[7]=14, 对齐到 4 的倍数 → 16
一个实实在在的省空间案例
假设要做一个礼品兑换单,商品有图书、杯子、衬衫三类,各自还带不同属性。如果用一个结构体装下所有属性,就会又大又浪费:
// 优化前:图书根本用不到 "design、colors、sizes",却很占地方
struct gift_list {
int stock_number; double price; int item_type;
char title[20]; char author[20]; int num_pages; // 图书
char design[30]; int colors; int sizes; // 杯子/衬衫
};
优化思路:公共属性单独列出,剩余「不同商品自己才用」的属性放进联合体:
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; // 三种商品共用这块最大的空间
};
这样内存一下就"瘦"下来了。
联合体的另一个妙用:判断大小端
int check_sys() {
union { int i; char c; } un;
un.i = 1;
return un.c; // 返回 1 是小端,返回 0 是大端
}
枚举:把可能的取值一个个列出来
枚举顾名思义就是「一一列举」可能的取值:
enum Color { RED, GREEN, BLUE };
enum Week { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
这些常量本质是整数,默认从 0 开始依次 +1(RED=0, GREEN=1, BLUE=2),也可以手动改,比如 RED = 5。
枚举的几大优点:
- 可读性/可维护性好:switch 里写
ADD比写1明白多了。 - 比
#define更严谨:有类型检查。 - 便于调试:预处理会删掉
#define,但枚举常量会保留在调试信息里。 - 一次可以定义多个常量,且遵循作用域规则。
✿ 摘要
- 联合体所有成员共用同一块内存,大小为最大成员并对齐到最大对齐数。
- 联合体适合「互斥使用」的场景,能明显节省内存。
- 联合体还能优雅地判断机器大小端。
- 枚举列举可能的取值,常量默认从 0 递增,可手动改值。
- 枚举比宏多类型检查、易调试、可读性高等优点。
愿当下的花如你所见般美丽
评论交流
欢迎留下你的想法