先赞后看已成习惯!!!
联合体
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 定义的符号
- 使用方便,⼀次可以定义多个常量
- 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使用
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!!!点个赞走吧!!!