C语言、自定义类型:联合体、枚举
📚 目录
- 1.联合体声明定义
- 1.联合体的特点
- 1.联合体的内存大小
- 4.联合体与结构体的对比
- 5.联合体判断编译器的大小端
- 6.枚举类型的声明
- 7.枚举类型的优点
- 8.枚举类型的使用
前言:
今天我们又来学习一种自定义类型:联合体;那么什么是联合体和枚举呢?接下来我们就来学习学习。
联合体(也可以成为共用体):联合体就像一个一个结构一样,就好像结构体,都是由多个成员组合而成,这些成员可以是不同的类型,关键字:union
特点:编译器只为最大的内存分配空间,所有成员共用一块内存空间;给联合体内任意一个成员赋值,其他成员的值也跟着发生改变。
1. 联合体的声明定义
接下来演示联合体的声明定义
#include<stdio.h>//联合体类型的声明unionpf{chara;intc;};intmain(){//联合体类型定义unionpf opp={0};return0;}以上就是我们联合体简单的声明和定义。
2. 联合体的特点
联合体的成员是共用一块内存空间的,联合体的内存大小至少是最大成员体的内存大小;只有这样才能保证每一个联合体成员都能够存得下。
我们通过Vs调试窗口内存来探究他的结果:
代码1:
#include<stdio.h>//联合体类型的声明unionpf{chara;intc;};intmain(){//联合体类型定义unionpf opp={0};//打印每个成员的地址printf("%p\n",&opp);printf("%p\n",&(opp.a));printf("%p\n",&(opp.c));return0;}代码2:
#include<stdio.h>//联合体类型的声明unionpf{chara;intc;};intmain(){//联合体类型定义unionpf opp={0};opp.c=0x11223344;opp.a=0x55;printf("%x\n",&(opp.a));return0;}
代码1:我们发现了他们三个的结果都是相同的第一个地址。
我们再看看他opp.c的内存和opp.a的内存地址。
代码2:我们发现了原本opp.c这个位置原本上应该存放的是0x11223344这里的44被opp.a里面的0x55给占用了。
从结果上看,我们得到的地址都是相同的地址,这就说明了联合体每个成员的内存大小都是共用的。
联合体共用内存情况:
4个字节分别对应着4个地址。
3. 联合体的内存大小
那么我们联合体的内存大小是怎么算的呢?
联合体的大小最小为最大成员的内存大小。
当联合体中最大内存成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
例如:
//计算下列结构体的大小。#include<stdio.h>unionpf1{chara[5];intc;};unionpf2{shorta[7];intc;};intmain(){printf("%zu\n",sizeof(unionpf1));printf("%zu\n",sizeof(unionpf2));return0;}结果:
为什么会是这个结果呢?我们来分析一下。
4.结构体与联合体的对比
那么结构体和联合体有什么区别呢?
structS{charc;inti;};unionUn{charc;inti;};#include<stdio.h>intmain(){structSs={0};unionUn un={0};return0;}
我们通过图片可以知道结构体的内存浪费比较大,而我们联合体浪费的内存远远没有结构体那么多。当我们结构体里面内存非常多的时候,浪费的内存也会不断增多。
而我们的联合体采用的是共用内存空间的形式,对于内存的利用比较高。
总结:联合体可以适当减少内存,但是当我们给其中一个成员赋值的时候,其他成员的值也会发生改变。
联合体判断编译器的大小端
#include<stdio.h>inttest(){union{//建立一个联合体inti;charc;}un;un.i=1;returnun.c;//因为是联合体所以c和i的内存是共用的,我们返回char类型的c让他访问一个字节。返回1是小端返回0是大端}intmain(){intr=test();if(r==1){printf("小端\n");}else{printf("大端\n");}return0;}
我们使用的Vs编译器为小端。
枚举类型:
枚举:就是一个一个把可能的值给列举出来。
就像我们生活中星期一到星期天、月份、颜色、价格等等这些东西给一一列举出来。像这些数字我们就能够使用枚举给他们列出来。
在以后写代码过程中避免不了大量的代码,代码一多就会出现各种各样的问题。
例如:(以订单为例子) ```c#include<stdio.h>//我们用#defind定义了一些毫无关系的常量#defineORDER_PENDING_PAYMENT1#defineORDER_PENDING_DELIVERY2#defineORDER_DELIVERED3#defineORDER_COMPLETED4voidList(intstatus){switch(status){caseORDER_PENDING_PAYMENT:printf("订单待付款\n");break;caseORDER_PENDING_DELIVERY:printf("订单待发货\n");break;case30:printf("订单已发货\n");break;caseORDER_COMPLETED:printf("订单已完成\n");break;default:printf("状态未知\n");break;}}intmain(){List(3);return0;}问题1:常量无归类,代码量大了后难以管理
问题2:容易写错值(比如把3写成30),编译器无法校验
问题3:无法直观看出这些常量是一组的
调用时只能传数字,语义不清晰
6.枚举类型的声明
举例我们上面的例子:
#include<stdio.h>enumDay{Mon,Tues,Wed,Thur,Fri,Sat,Sun};颜色
enumColor{RED,GREEN,bLUE};注意:
我们每写完一个枚举成员用逗号隔开而不是分号,最后一个枚举成员不用添加分号。
在枚举成员{ }外面必须添加分号。
我们定义的枚举类型的成员可能都是有值的,默认从1开始,依次加1在声明枚举类型的时候我们可以进行赋值。
例如:
enumColor{RED=3,GREEN=4,bLUE=6};当我们进行赋值完成后,在使用过程中就类似#defind定义常量,如果只对第一个进行了赋值,那么后面的就会在第一个的基础上加1。
enumColor{RED=9,GREEN,//这里就会变成10bLUE// 这里就会变成11};7.枚举类型的优点
我们知道了#defind也能定义常量,为什么还会有枚举呢?
我们就要学学枚举的优点了。
优点:
增加我们代码的可读性和可维护性;#define 定义的常量是全局的,无归属关系,易命名冲突。
相比较#defind我们的枚举有类型检查,更加严谨。
枚举变量本质是整型变量,所以可以用%d输出其数值。
枚举成员是编译期常量,不能修改
便于调试。我们编译器在编译过程中会删掉#defind定义的符号。
8.枚举类型的使用
例如:
enumColor{RED=1,GREEN=2,BLUE=3};intmain(){enumColorr=GREEN;//使⽤枚举常量给枚举变量赋值return0;}完!
