1. 联合体的特点
联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。
#include <stdio.h>
union Un
{
char c;
int i;
};
int main() {
union Un un;
printf("%d\n", sizeof(un)); // 4
return 0;
}
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
#include <stdio.h>
union Un
{
char c;
int i;
};
int main() {
union Un un;
printf("%p\n", &un);
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i);
return 0;
}
- 因为是共用一块内存空间,所以对于起始地址而言三者都是一样的。
- 0x11223344实际上在内存中是以小端字节序存储:44 33 22 11,联合体的内存空间对每个成员而言是共用的,只是每个成员能访问的大小根据自身的数据类型决定,i能使用4个字节,c则能使用1个字节,结果为11223355的原因想必不难理解。
2. 计算联合体占用内存大小
- 联合的大小至少是最大成员的大小。
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
#include <stdio.h>
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
int main() {
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}
Un1的最大对齐数不是5!char数组实际上只是算作5个char类型变量。i的大小作为对齐数,但却不是最大成员,char数组才是最大成员,4个字节存不下char数组(5个字节),所以要对齐到4的倍数8才能存下。Un2相同道理。
3. 利用联合体的特点判断当前机器是以什么字节序顺序存储数据?
#include <stdio.h>
union Un1
{
char c;
int i;
};
int main() {
union Un1 un;
un.i = 1;
if (un.c == 1) {
printf("小端字节序");
}
else {
printf("大端字节序");
}
return 0;
}
1在内存中如果是以小端字节序存储的,那么是这个样子:00000001 00000000 00000000 00000000(十六进制:01 00 00 00)。c是char类型,只能访问1个字节大小的数据,如果访问到的值是1,说明当前机器就是小端字节序存储数据。
4. 联合体什么时候使用?
某些成员不会同一时间使用,这时使用联合体是可以节省空间的。
比如某个商店有一个活动要上线一个礼品兑换单,兑换单中有三种商品:图书、杯子、衬衫。
这三个商品都有互相相同的信息:库存量、价格和商品类型。
不同的信息则有:
- 图书:书名、作者和页数。
- 杯子:设计。
- 衬衫:设计、可选的颜色和尺寸。
如果我们不思考太多直接使用下面设计的结构体:
struct gift_list {
// 公共属性
int stock_number;
double price;
int item_type;
// 图书
char book_name[20];
char author[30];
int page_nums;
// 杯子和衬衫共有
char design[30];
// 衬衫
int colors;
int sizes;
};
这样做实际上会浪费许多内存,比如对于图书而言,设计、颜色和尺寸并不会去用或者说并不重要,对于杯子和衬衫而言,书名、作者和页数更不可能用到。
如果只把公共属性摘出来放在结构体中,因为这是必须要有的。然后再把各个商品本身的属性放在联合体内,这样在一定程度上节省了内存开销。
struct gift_list {
// 商品的公共属性
int stock_number;
double price;
int item_type;
union {
struct {
char book_name[20];
char author[30];
int page_nums;
} book; // 图书
struct {
char design[30];
} mug; // 杯子
struct {
char design[30];
int colors;
int sizes;
} shirt; // 衬衫
} item; // 商品
};
在联合体内,最大空间的毫无疑问是图书,存放图书数据的大小存放其它两种商品肯定是没问题的,在同一时间里不会浪费太多内存空间。