写点什么

【结构体内功修炼】枚举和联合的奥秘(三)

作者:Albert Edison
  • 2022 年 10 月 07 日
    四川
  • 本文字数:2709 字

    阅读完需:约 9 分钟

【结构体内功修炼】枚举和联合的奥秘(三)

1. 枚举

枚举顾名思义就是一一列举。


把可能的取值一一列举。


比如我们现实生活中:


1、一周的星期一到星期日是有限的 7 天,可以一一列举。


2、性别有:男、女、保密,也可以一一列举。


3、月份有 12 个月,也可以一一列举


这里就可以使用枚举了。

🍑 枚举类型的定义

📝 代码示例


enum Day//星期{  Mon,  Tues,  Wed,  Thur,  Fri,  Sat,  Sun};
enum Sex//性别{ MALE, FEMALE, SECRET};
enum Color//颜色{ RED, GREEN, BLUE};
复制代码


以上定义的 enum Dayenum Sexenum Color 都是枚举类型。


{ }中的内容是枚举类型的可能取值,也叫 枚举常量


这些可能取值都是有值的,默认从 0 开始,一次递增 1,当然在定义的时候也可以赋初值。


📝 代码示例


#include <stdio.h>
enum Sex//性别{ MALE, FEMALE, SECRET};

int main(){ printf("%d\n", MALE); printf("%d\n", FEMALE); printf("%d\n", SECRET);
return 0;}
复制代码


🌟 运行结果


🍑 枚举的优点

为什么使用枚举?


我们可以使用 #define 定义常量,为什么非要使用枚举?


#define MALE 4#define FEMALE 5#define SECRET 6
复制代码


枚举的优点:


1、增加代码的可读性和可维护性;


2、和 #define 定义的标识符比较枚举有类型检查,更加严谨;


3、防止了命名污染(封装);


4、便于调试, #define 定义的常量是不能进行调试的


5、使用方便,一次可以定义多个常量

🍑 枚举的使用

📝 代码示例


#include <stdio.h>
enum Color//颜色{ RED = 1, GREEN = 2, BLUE = 4};
int main(){ enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;
return 0;}
复制代码

2. 联合(共用体)

🍑 联合类型的定义

联合也是一种特殊的自定义类型;


这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫 共用体)。


📝 代码示例


#include <stdio.h>
union Un{ char c; int i;};
int main(){ union Un u;
printf("%d\n", sizeof(u));
return 0;}
复制代码


那么 u 占多少个字节呢?我们打印看一下👇



为什么是 4 呢?


别急,我们把 u 和它的成员地址全部打印出来看一看



我的天啊,它们三个的地址为啥都是一样的呢?


uu.cu.i 它们都指向第 1 个字节首地址;


c1 个字节,i4 个字节;


也就是 ic 共用了第 1 个字节;


当我给 c 赋值的时候,我就把 i 的第一个字节给改变了;


当我给 i 赋值的时候,整个 c 也就被改了;



所以 联合体 比较特殊的地方在于:对于联合体的成员在同一时间只能用 1 个;


📝 代码示例


#include <stdio.h>
union Un{ char c; int i;};
int main(){ union Un u = { 0 };
u.c = 'w';
u.i = 0x11223344;
return 0;}
复制代码


我们在内存中看一下调试结果👇


首先把第 1 个字节改为 w



然后又把整个 i 的内容改为 0x1223344


🍑 联合的特点

1、联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小;


2、因为联合至少得有能力保存最大的那个成员;

🍑 联合的应用

比如我现在要设计一个 学校用户系统 👇


1、学生:姓名、年龄、身份


2、老师:姓名、年龄、职称


📝 代码示例


union type{  identity; //身份  title; //职称};
struct UserInfo{ char name[20]; int age; union type t;};
复制代码


身份职称 都是相似的值,但它们只会用 1 个;


来看一道面试题:判断当前计算机的大小端存储


首先来看看什么是 大小端字节序


1、小端存储:假设 01 是低位字节的内容,00 是高位字节的内容,把低位字节的内容 01 放在低地址处,高位字节的内容 00 放在高地址处,这种存储方式叫 小端存储



1、大端存储:假设 01 是低位字节的内容,00 是高位字节的内容,把低位字节的内容 01 放在高地址处,高位字节的内容 00 放在低地址处,这种存储方式叫 大端存储



那么如何用代码来实现呢?


其实很简单,我们可以拿出第 1 个字节的内容,如果第 1 个字节的内容是 1,那么就是 小端存储;如果第 1 个字节的内容是 0,那么就是 大端存储


📝 代码实现


#include <stdio.h>
int check_sys() { int a = 1; return (*(char*)&a);}
int main(){ int ret = check_sys();
if (1 == ret) { printf("大端\n"); } else { printf("小端\n"); }
return 0;}
复制代码


🌟 运行结果



我们可以看到,aint 类型,但我们在 check_sys() 实际使用的只有 1 个字节,那么对代码进行升级;


📝 代码升级


#include <stdio.h>
int check_sys() { union { char c; int i; }u;
u.i = 1; return u.c;}
int main(){ int ret = check_sys();
if (1 == ret) { printf("大端\n"); } else { printf("小端\n"); }
return 0;}
复制代码


🌟 运行结果



这就是巧妙的运用到了 联合体联合体 的成员会共用一块儿空间;

🍑 联合大小的计算

1、联合的大小至少是最大成员的大小。


2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。


📝 代码示例一


#include <stdio.h>
union Un1{ char c[5]; int i;};
int main(){ printf("%d\n", sizeof(union Un1)); return 0;}
复制代码


成员 c 的类型是 char,所以它的对齐数是按照 char 来算的,也就是 1,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 1


成员 i 的类型是 int,所以它的对齐数是按照 int 来算的,也就是 4,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 4


成员 c 的对齐数是 1,成员 i 的对齐数是 4,那么最大的对齐数就是 4,而联合体的总大小必须是最大对齐数的整数倍;


又因为 cchar 类型的数组,有 5 个元素,所以有 5 个字节;iint 类型,有 4 个字节;所以最大的就是 5 字节,但最大的对齐数是 4,不满足,所以就就是 8,也就是 42 倍。


🌟 运行结果



📝 代码示例二


#include <stdio.h>
union Un2{ short c[7]; int i;};
int main(){ printf("%d\n", sizeof(union Un2)); return 0;}
复制代码


cshort 类型,占 2 字节,有 7 个元素,所以占 14 字节;iint 类型,占 4 字节;


那么取 14 就能存放下 Un2 的所有成员了,但是 14 是不是最大对齐数的整数倍呢?


成员 c 的类型是 short,所以它的对齐数是按照 short 来算的,也就是 2,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 2


成员 i 的类型是 int,所以它的对齐数是按照 int 来算的,也就是 4,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 4


成员 c 的对齐数是 2,成员 i 的对齐数是 4,那么最大的对齐数就是 4,而联合体的总大小必须是最大对齐数的整数倍,14 不是 4 的倍数,怎么办呢?


很简单,浪费掉 2 字节变成 16 就是 4 的倍数了。


🌟 运行结果



发布于: 刚刚阅读数: 4
用户头像

Albert Edison

关注

目前在某大厂担任后端开发,欢迎交流🤝 2022.03.08 加入

🏅️平台:InfoQ 签约作者、阿里云 专家博主、CSDN 优质创作者 🛫领域:专注于C语言、数据结构与算法、C++、Linux、MySQL、云原生的研究 ✨成就:2021年CSDN博客新星Top9,算法领域优质创作者,全网累计粉丝4W+

评论

发布
暂无评论
【结构体内功修炼】枚举和联合的奥秘(三)_C语言_Albert Edison_InfoQ写作社区