目录
- 前言
- 一、联合体
- 1.1 联合体类型的声明
- 1.2 联合体的特点
- 1.3 相同成员的结构体和联合体对比
- 1.4 联合体大小的计算
- 1.5 联合体的⼀个练习
- 总结
前言
前面我讲到C语言中的自定义结构——结构体,其实C语言中的自定义结构不只有结构体,还有枚举和联合体,我们今天就来学习一下这两个C语言中的自定义类型的其中一个——联合体;话不多说,正文开始:
一、联合体
1.1 联合体类型的声明
像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。
但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体。
给联合体其中⼀个成员赋值,其他成员的值也跟着变化。
这是什么意思呢?
union Un
{
char c;
int i;
};
int main()
{
union Un un = { 0 };
printf("%zd\n", sizeof(un));
return 0;
}
大家可以猜猜这个结构体是多大字节的:
为啥是4呢?
1.2 联合体的特点
联合的成员是共⽤同⼀块内存空间的,这样⼀个联合变量的⼤⼩,⾄少是最⼤成员的⼤⼩(因为联合⾄少得有能⼒保存最⼤的那个成员)。
union Un
{
char c;
int i;
};
int main()
{
//联合变量的定义
union Un un = { 0 };
printf("%zd\n", sizeof(un));
// 下⾯输出的结果是⼀样的吗?
printf("%p\n", &un);
printf("%p\n", &(un.i));
printf("%p\n", &(un.c));
return 0;
}
他们的地址一样?到这我们就不难理解联合体的共用空间是什么意思了:
那也就是说两个成员不能同时使用,如果同时使用,会互相干扰,我们来验证一下:
union Un
{
char c;
int i;
};
int main()
{
union Un un = { 0 };
un.i = 0x11223344;
un.c = 0x55;
printf("%x ", un.i);
return 0;
}
运行结果:
代码1输出的三个地址⼀模⼀样,代码2的输出,我们发现将i的第4个字节的内容修改为55了。我们仔细分析就可以画出,un的内存布局图。
1.3 相同成员的结构体和联合体对比
我们再对⽐⼀下相同成员的结构体和联合体的内存布局情况。
1.4 联合体大小的计算
通过刚刚的例子,我们对联合体的大小有了初步的认识,联合体的大小是最大成员的大小?
我们来看看下面的例子:
union Un
{
char c[5];
int i;
};
int main()
{
union Un un = { 0 };
printf("%zd\n", sizeof(un));
return 0;
}
这个结果是否是5,我们来看看结果:
结果与我们想的并不一样,那联合体的大小到底如何计算,我们往下看:
• 联合的⼤⼩⾄少是最⼤成员的⼤⼩。
• 当最⼤成员⼤⼩不是最⼤对⻬数的整数倍的时候,就要对⻬到最⼤对⻬数的整数倍
char [5]的类型是char,所以他的对齐数就是1,int i的对齐数就是4,所以联合体的大小必须是4的倍数,最小是5,所以结果为8;
来点练习:
union Un2
{
short c[7];
int i;
};
int main()
{
//下⾯输出的结果是什么?
printf("%d\n", sizeof(union Un2));
return 0;
}
结果可以在评论区打出
使⽤联合体是可以节省空间的,
举例:
⽐如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。
每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
图书:书名、作者、⻚数
杯⼦:设计
衬衫:设计、可选颜⾊、可选尺⼨
那我们不耐⼼思考,直接写出⼀下结构
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;//尺⼨
};
上述的结构其实设计的很简单,⽤起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的⼤⼩就会偏⼤,⽐较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常⽤的。⽐如:
商品是图书,就不需要design、colors、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;
};
1.5 联合体的⼀个练习
写⼀个程序,判断当前机器是⼤端?还是⼩端?
这里我们利用联合体共用空间的特点,我们创建一个联合体,里面放一个int类型和char类型,我们赋值个int类型1,然后返回char如果是1则是小端,0则是大端;
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;//返回1是⼩端,返回0是⼤端
}
这个代码两个字形容:优雅;
我们可以验证一下:
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;//返回1是⼩端,返回0是⼤端
}
int main()
{
if (check_sys() == 1)
printf("小端");
else
printf("大端");
return 0;
}
结果是如我们所料,VS是小端存储;
总结
到这我们对联合体有了基本的了解,再日后通过进一步使用,我们可以掌握联合体的使用规则,到这这期就结束了,下期我们来讲C语言的最后一个自定义类型——枚举,下期见。