• 【C语言】自定义类型:联合和枚举


    在这里插入图片描述

    前言
    自定义类型有三种:结构体,联合体以及枚举。在上一篇博客中我们已经讲解了结构体,接下来我们将学习联合体和枚举。


    一、联合体

    1.1 联合体的声明

    联合体(Union)是一种特殊的数据结构,允许在同一内存位置存储不同的数据类型。与结构体不同,联合体的各个成员共享同一块内存空间,因此联合体的大小等于其最大成员的大小 (当最大成员大小等于最大对齐数的整数倍时) 。这意味着在联合体中只能存储一个成员的值,而不是多个成员的值。

    //联合体示范
    union MyUnion {
        int i;
        float f;
        char c;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这个示例中,MyUnion 是一个联合体,它可以存储一个整数 i、一个浮点数 f 或一个字符 c。这些成员共享同一块内存空间,因此在任何时候只能存储其中一个成员的值。

    1.2 内存中的联合体成员

    联合的成员是共用⼀块内存空间的,以下几个例子来证明:

    //代码1
    #include 
    //联合类型的声明
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行结果:
    在这里插入图片描述
    由此可见,无论是任何一个联合体成员,还是联合体本身,它们的地址是一样的


    再来看联合体成员在内存中的数据:

    //代码2
    #include 
    //联合类型的声明
    union Un{
    	char c;
    	int i;
    };
    
    int main(){
    	//联合变量的定义
    	union Un un = { 0 };
    	un.i = 0x11223344;
    	un.c = 0x55;
    	printf("%x\n", un.i);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    结果如下:
    在这里插入图片描述
    当我们把16进制的11223344赋值给i,又把55赋值给c,后来我们想取出 i 时发现,其中一部分已经被c覆盖了。

    当我们使用联合体时,可以看到,c和i是共用一个内存,且给un.c赋值时会覆盖掉一个字节的内容
    在这里插入图片描述

    1.3 联合体的大小计算

    有以下两个条件:

    • 联合的⼤小必须大于或等于是最⼤成员的⼤⼩。
    • 联合体的大小应当是最大对齐数的整数倍

    举例:

    #include 
    union Un1{//Un1的大小大于或等于5(5个char>1个int),又Un1的大小应当是4的整数倍,所以Un1的大小是8
    	char c[5];//char大小为1,默认对齐数8,对齐数1
    	int i;    //int大小为4,默认对齐数8,对齐数4
    };
    
    union Un2{//Un2的大小大于或等于14(7个short>1个int),又Un2的大小应当是4的整数倍,所以Un1的大小是16
    	short c[7];//short大小为2,默认对齐数8,对齐数2
    	int i;     //int大小为4,默认对齐数8,对齐数4
    };
    
    int main(){
    	//下⾯输出的结果是什么?
    	printf("%d\n", sizeof(union Un1));
    	printf("%d\n", sizeof(union Un2));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果如下:

    在这里插入图片描述


    1.4 对比联合体和结构体的内存使用情况

    //结构体
    struct S{
     char c;
     int i;
    };
    struct S s = {0};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    //联合体
    union Un{
     char c;
     int i;
    };
    union Un un = {0};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    显而易见,联合体更加节省空间,但由于联合体的成员共用一个内存空间,所以联合体的使用是有限制的
    在这里插入图片描述


    1.5 联合的使用场景

    例如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书、杯⼦、衬衫。每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

    • 图书:书名、作者、⻚数
    • 杯子:设计
    • 衬衫:设计、可选颜⾊、可选尺⼨
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    因为每一种商品都有自己独特的属性,当我们描述一种商品时需要库存量、价格、商品类型以及仅描述该商品的特殊属性。这时联合体比结构体更加节省空间。因此使用哪一种自定义类型取决于描述的对象。


    二、枚举类型

    2.1 枚举类型的声明

    枚举类型(Enum)是一种用于定义命名整数常量的数据类型。 允许程序员为一组相关的整数值分配有意义的名称,以提高代码的可读性和可维护性。

    enum 枚举名称 {
        枚举值1,
        枚举值2,
        // 可以有更多的枚举值
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    举例,列举颜色:

    #include
    enum Color{//颜⾊
    	RED,
    	GREEN,
    	BLUE
    };
    int main() {
    	printf("%d %d %d",RED,GREEN,BLUE);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果:
    在这里插入图片描述
    枚举常量的从0开始,当然我们可以自己赋值:

    #include
    
    enum Color{//颜⾊
    	RED,
    	GREEN=5,
    	BLUE
    };
    int main() {
    	printf("%d %d %d",RED,GREEN,BLUE);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行结果:
    在这里插入图片描述

    2.2 枚举的优点

    枚举的优点:

    1. 增加代码的可读性和可维护性
    2. 和#define定义的标识符⽐较枚举有类型检查,更加严谨。
    3. 便于调试,预处理阶段会删除 #define 定义的符号
    4. 使用⽅便,⼀次可以定义多个常量
    5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使用

    2.3 枚举的应用场景

    1. 定义枚举类型
    enum Weekday {
        MONDAY,
        TUESDAY,
        WEDNESDAY,
        THURSDAY,
        FRIDAY,
        SATURDAY,
        SUNDAY
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 声明和使用枚举变量
    enum Weekday today = TUESDAY;
    
    • 1
    1. 使用枚举值
    if (today == MONDAY) {
        printf("今天是星期一\n");
    } else if (today == TUESDAY) {
        printf("今天是星期二\n");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 开关语句中的枚举
    switch (today) {
        case MONDAY:
            printf("今天是星期一\n");
            break;
        case TUESDAY:
            printf("今天是星期二\n");
            break;
        // 其他星期几的情况
        default:
            printf("今天不是星期一或星期二\n");
            break;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    枚举的使用与#define定义常量类似,但枚举和#define定义的标识符⽐较枚举有类型检查,更加严谨。


    在这里插入图片描述
    如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
    欢迎大家提出疑问,以及不同的见解。

  • 相关阅读:
    机器学习 LabelEncoding OnehotEncoding
    Ansible的介绍与安装
    用友U8 crm客户关系管理存在任意文件上传漏洞2 附POC
    Java多线程开发系列之六:无限分解流----Fork/Join框架
    Java 反射
    圆满收官!华秋电子亮相2022慕尼黑华南电子展,数字化平台赋能智能制造
    iNFTnews | 如果完美只存在于虚拟世界,你会爱真实的我吗?
    echarts-初识
    猿创征文|零基础python学习之旅(简短又漫长)
    一篇文章扒掉“桥梁Handler”的底裤
  • 原文地址:https://blog.csdn.net/weixin_73551991/article/details/133166773