联合体
1. 联合体的定义
联合体又叫共用体,它是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。给联合体其中⼀个成员赋值,其他成员的值也会跟着变化。
联合体的结构类似于结构体,由关键词union和多个成员变量构成:
union (union tag)
{
member definition;
member definition;
…
member definition;
} [more union variables];
union tag为用户自己编译;member definition为成员变量:可以为 int char等等;
[more union variables]为你设置的联合体名称
2.联合体类型的声明
我们来看一下这个代码:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> //联合类型的声明 union Un { char c; int i; }; int main() { //联合变量的定义 union Un un = { 0 }; //计算连个变量的⼤⼩ printf("%d\n", sizeof(un)); return 0; }
输出值为: 4
为什么是4呢?
在我们设定的联合体中,存在char(1字节)、int(4字节)类型,在联合体的定义中,联合体的成员会共同占用一块内存空间,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)
(1)联合体
union Un { int n; char un; };
(2)联合体嵌套
union Un1 { int n; char un; }; union Un2 { int n; char un; union Un1; };
(3)匿名联合体
union { int n; char un; };
(4)自定义联合体
typedef union un { int n; char un; }un1;
让我们在来看下面两段代码
代码1:
#include <stdio.h> //联合类型的声明 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; }
000000EA08B3FAE4
000000EA08B3FAE4
000000EA08B3FAE4
我们会发现他们都指向同一个地址;
代码2:
#include <stdio.h> //联合类型的声明 union Un { char c; int i; }; int main() { //联合变量的定义 union Un un = { 0 }; un.i = 0x11223344; un.c = 0x11; //这里是16进制 printf("%x\n", un.i); return 0; }
这里的操作方法与结构体类似,可以利用(.)和(->)操作符
我们再来看看代码2中的输出:
输出: 11 22 33 11
有什么不同的吗 ?
我们发现在最后位置的44受un.c的赋值的影响变为了11;
3.相同成员的结构体和联合体对比
struct S union un { { char c; char c; int i; int i; }; }; struct S s = {0}; union Un un = {0};
结构体与联合体在内存中的区别
4.联合体的大小计算
- 至少是最大成员的大小
- 当最大成员大小不是最大对齐数的整数倍,就要对齐到最大对齐数的整数倍
使用联合体是可以节省空间的,对于具有公共属性的成员时我们就可以利用联合体节省空间:
例如:当我们购买商品时
公共属性:
//商品名
//价格
//类型
......
私有属性:
//书名
//出版商
//作者
......
5.利用联合体判断大小端
回顾:
#include<stdio.h> int check_sys() { int i = 1; return (*(char*)&i); //先取出i的地址,再将i的(int*)转化为char*,最后在解引用,取出低地址的一个字节; } int main() { int ret = check_sys(); //返回1,则说明低字节放在低地址 //返回0,则说明高字节放在低地址 if (ret = 0) { printf("大端存储"); } else { printf("小端存储"); } return 0; }
在前面中我们是利用char*和int*读取的字节大小的不同所判断;在这里我们也可以利用相同的原理使用联合体来判断
int check_sys() { union { int i; char c; }un; un.i = 1; return un.c; //返回1是⼩端,返回0是⼤端 } int main() { int ret = check_sys(); if (ret == 1) { printf("⼩端\n"); } else { printf("⼤端\n"); } return 0; }
枚举
1.枚举的声明
枚举意为-->列举
(1) 普通枚举
接下来我们举个例子,比如:我们要定义一个星期 , 使用#define 来为每个整数定义一个别名:
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
我们会发现这个的代码量就比较多,接下来我们看看使用枚举的方式:
enum DAY
{
MON=1, //指定从1开始,否则默认从0开始
TUE,
WED,
THU,
FRI,
SAT,
SUN
};
这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。
(2) 匿名枚举
和匿名结构体与匿名联合体类似,枚举也有匿名类型。
enum { APPLE, BANANA, ORANGE };
(3) typedef枚举
我们也可以使用typedef简化枚举。
typedef enum DAY { MON = 1, //指定从1开始,否则默认从0开始 TUE, WED, THU, FRI, SAT, SUN }DAY;
7.2 打印枚举常量
typedef enum DAY { MON, TUE, WED, THU, FRI, SAT, SUN }DAY; int main() { for (int i = MON; i < SUN; i++) { printf("%d ", i); } return 0; }
2.枚举的优点
我们可以使用#define 定义常量,为什么非要使用枚举?
枚举的优点:
- 增加代码的可读性和可维护性和#define定义的标识符比较枚举有类型检查,更加严谨。
- 便于调试,预处理阶段会删除 #define 定义的符号
- 使用方便,⼀次可以定义多个常量
- 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使用
3.枚举的应用
#include <stdio.h> int main() { enum color { red = 1, green, blue //red = 1 是为了防止输入1时,输出为green }; //枚举了 enum color favorite_color; //用户输入数字来选择颜色 printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): \n"); scanf("%d", &favorite_color); switch (favorite_color) { case red: printf("你喜欢的颜色是red\n"); break; case green: printf("你喜欢的颜色是green\n"); break; case blue: printf("你喜欢的颜色是blue\n"); break; default: printf("你没有选择你喜欢的color\n"); } return 0; }#include <stdio.h> int main() { enum color { red = 1, green, blue //red = 1 是为了防止输入1时,输出为green }; //枚举了 enum color favorite_color; //用户输入数字来选择颜色 printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): \n"); scanf("%d", &favorite_color); switch (favorite_color) { case red: printf("你喜欢的颜色是red\n"); break; case green: printf("你喜欢的颜色是green\n"); break; case blue: printf("你喜欢的颜色是blue\n"); break; default: printf("你没有选择你喜欢的color\n"); } return 0; }
oi!!!点个赞走吧!!!