一.联合体
1.联合体类型的声明
联合体像结构体一样,也是有一个或者多个成员组成,当然也可以不同的类型。但不同的是,比编译器只为最大的成员分配足够的内存空间,所有成员共用同一块内存空间。所以联合体也叫做:共用体。
联合体与结构体最不同的是,给联合体里的一个成员赋值,其他的成员也会随之变化。
联合体的声明其实也跟结构体大体一样
union Un
{char c;int i;
};
#include <stdio.h>
int main()
{union Un u = { 0 };printf("%zd", sizeof(u));return 0;
}
其实就是把struct给换成了union。
2.联合体的特点
上面的代码打印出来最终是4。可为什么是4呢?我们来探讨一下
首先,我们先思考一下,我上面说了一个东西就是所有成员共用一块空间。那么我在这个联合体里c和i的地址一样吗?我们来打印测试一下这两个地址是否一样。
其实是一样的。那么我们是不是可以得出一个结论:我们创建的一个成员变量i占了4个字节,这个c占了一个字节,其实i的第一个字节同样也是c的那一个字节。
再来看这个代码
union Un
{char c;int i;
};
#include <stdio.h>
int main()
{union Un u = { 0 };u.i = 0x11223344;u.c = 0x55;return 0;
}
再来看在内存中的存储,我改变了u.c的值,同样这里的44变成了55.
3.联合体大小的计算
想要计算联合体的大小,需要先明白两点
1.联合的大小至少是最大成员的大小
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
注意了,联合体的大小是至少是最大成员的大小,可不一定是最大成员的大小,举个例子:
#include<stdio.h>
union Un
{ //类型大小 默认对齐数 对齐数char c[5];//1 8 1int i; //4 8 4
};
int main()
{union Un u = { 0 };printf("%d", sizeof(u));return 0;
}
打印出来的是8
因为c有5个char类型的元素。直接就占用了5个字节,根据上面的第二点,我们需要对齐到4的倍数,所以就是8.
4.联合体的使用
根据我前面所说的,使用联合体我们是可以节省空间的。
那么假如我们举行了一个游戏,参与游戏的人,获得了礼品兑换的机会。有三种商品我们可以兑换:图书,杯子和衬衫。而每一种商品都有:库存量,价格等其他信息。
还有一些商品的特有属性
图书:书名,作者,页数
杯子:设计
衬衫:设计,颜色,尺寸
如果我想用代码把这些结构写出来,如果不认真思考的话,可能就直接把这些一窝蜂的都写到结构体里去了。
可能写出来是这样的
struct gift_list
{//公共属性int stock_number;//库存量double price;//定价int item_type;//商品类型//特殊属性char title[20];//书名char author[20];//作者int num_pages;//页数char design[30];//设计int color;//颜色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 color;//颜色int sizes;//尺寸}shirt;}item;
};
在这里有一个联合体里面包含了三个结构体成员,我们把每一件物品的特属性都分别放在了book,mug和shirt里面,前提是当我们在使用其中一个的时候是不会影响其他的两个,这时我们就可以使用联合体的方式来很大程度的节省空间。
5.联合体的小练习
写一个程序来判断当前机器是大端还是小段
#include <stdio.h>
int check_sys()
{union Un{char c;int i;}u;u.i = 1;return u.c;
}
int main()
{int ret = check_sys();if (ret = 1){printf("是小端\n");}else{printf("是大端");}return 0;
}
可以复制来看一下打印出来的多少。
二.枚举类型
1.枚举类型的声明
所谓枚举,其实就是一一列举的意思。它的关键字是enum。比如三原色:
enum Color
{RED,GREEN,BLUE,
};
这就是把他们一一列举出来,{}里的内容也就是枚举类型的可能取值,也叫做枚举常量。枚举类型也是可以创建变量的,比如:
int main()
{enum Color color=RED;return 0;
}
值得注意的是,枚举内部的成员其实也有数值,我们可以单独打印出来它们的值来看一下。
#include<stdio.h>
enum Color
{RED,GREEN,BLUE,
};
int main()
{enum Color color=RED;printf("%d\n", RED);printf("%d\n", GREEN);printf("%d\n", BLUE);return 0;
}
最终打印出来的值按顺序分别是0,1,2
我们在主函数里是不能改变这三个值的,因为它们也是常量。但是,我们可以在枚举体的内部改变它们的值:
我们把第二个值改了之后,这里的第二个值和第三个值也随之变化了。
2.枚举类型的优点
1.增加代码的可读性和可维护性
2.和#define定义的标识符相比枚举有类型检查,更加严谨(#define定义的标识符是没有类型可言的,但是枚举是有类型的,比如我给一个enum Color =RED;在c++中就不能写成enum Color =0,其实RED就是0)
3.便于调试,预处理阶段会删除#define定义的符号(在预处理的时候,如果代码里有#define定义的标识符,会直接给替换掉)
4.使用方便,一次可以定义多个常量
5.枚举常量是遵循作用域规则的,枚举声明在函数里,只能在函数里使用
感谢大家的观看,如果有错误,还请大家多多指正。