目录
引言:
该篇我们来讲一讲C语言中所有的自定义类型,C语言中总共有 三个自定义类型,分别是结构体,联合体和枚举,他们的关键字分别是struct,union和enum,那么,接下来,我们来细致的讲讲每个自定义类型的使用,运用场景以及开创时的内存分配问题
结构体
1.结构体类型
1.1.结构体类型的声明
结构是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量,我们来随便写个结构体,如下图

1.1.1.结构的声明
结构体的声明其实就是结构体创建的过程,就像上面的那个代码就是结构体的声明,我们来举个描述学生的结构体的例子,代码如下
cpp
struct Student
{
char name[20];//姓名
char sex;//性别
char id[20];//学号
int age;//年龄
};
当然,我们可以用typedef对这个结构体进行重命名,因为这个结构体如果不重命名,要创建变量就要写struct Student这么长一串,但是重命名完后就很简单的,如下
cpp
typedef struct Student
{
char name[20];//姓名
char sex;//性别
char id[20];//学号
int age;//年龄
}Student;
Student a;//ok
1.1.2.结构体变量的创建和初始化
1.1.2.1.结构体变量的创建
结构体变量的创建主要有俩种方法
第一种:在声明结构体的时候顺便创建变量,如下代码
cpp
struct Student
{
char name[20];//姓名
char sex;//性别
char id[20];//学号
int age;//年龄
}a;
这个代码中的a就是创建的结构体变量
第二种:像正常创建变量一样创建变量,如下代码
cpp
struct Student a;
因为我们已经声明了有struct Student这么个结构体类型,所以就当正常类型创建就可以了
注:在C语言中,创建结构体变量的时候不可以省略struct,但在C++中,创建结构体变量的时候可以省略struct
1.1.2.2.结构体变量的初始化
这个初始化主要也分为俩种,只要是创建的结构体变量都可以用这俩种方式来初始化,不需要考虑是用什么方式创建的结构体变量
第一种:直接=接大括号,括号里面每个成员一个一个赋值,赋值顺序和结构体类型内部的成员类型顺序是一样的,我们来看一个代码来辅助理解
cpp
struct node
{
char a[10];
int b;
char c[20];
};
int main()
{
struct node pre = { "dsawd",3214,"oiwdq" };
return 0;
}
注:这种方法不可以实现跨成员初始化,只能前面的成员初始化完才可以初始化后面的成员,如果想要实现跨成员初始化的话就需要用到第二种初始化方法了
第二种:
通过结构体的操作符来找到对应成员赋予初值,代码如下
cpp
struct node
{
char a[10];
int b;
char c[20];
};
int main()
{
struct node pre = { .c = "xixi", .a = "ahh" };
return 0;
}
1.2.结构体类型的特殊声明
简单的结构体声明我们会了后,我们来看下不完全的结构体声明,即匿名结构体类型,代码如下
cpp
struct
{
char a[10];
int b;
char c[20];
}s;
int main()
{
return 0;
}
这便是结构体的特殊声明,区别在哪呢,就是结构体没了结构体名,就直接创建了一个结构体变量,这也就是匿名结构体,匿名结构体是无法再创建这种结构体的,因为都没有结构体名给你去找对应的结构体类型,所以只能用已经创建好的结构体变量
匿名结构体也可以进行重命名,重命名操作后,这个结构体就可以用很多次了(可以创建变量了),代码如下
cpp
typedef struct
{
char a[10];
int b;
char c[20];
}s;
如果没有对匿名结构体进行重命名操作的话,基本上只能使用一次,我们来看下面这个代码来加深理解
cpp
struct
{
char a[10];
int b;
char c[20];
}a;
struct
{
char a[10];
int b;
char c[20];
}b,*p;
p = &a;//err
这个代码中是俩个匿名结构体,这俩个结构体内的成员变量是一样的,那么,可以将第二个匿名结构体的指针指向第一个结构体吗
答案是不可以的,会报警告,原因很简单,正如我们刚刚所说,匿名结构体没有结构体名,所以我们不知道这结构体是属于什么结构体,编译器就会把每个匿名结构体当成完全不同的类型,那么都是不同的类型了,指向的话当然是非法了
1.3.结构体的自引用
结构体可以自引用吗,当然是可以的,但是要注意怎么引用
错误的自引用方式:
cpp
struct node
{
char a[10];
int b;
char c[20];
struct node d;
};
这就是典型的错误自引用案例,如果引用的是自身,那么这个node d就可以又拆分成a,b,c和一个结构体node,那么,一直往下,无穷尽 ,结构体就无穷大了
正确的自引用方式:
cpp
struct node
{
char a[10];
int b;
char c[20];
struct node* d;
};
这个其实跟数据结构里的链表功能有点相似了,这个d相当于是可以指向结构体类型的链表中的下一个结构体的位置
如果想要对结构体重命名了,在结构体自引用的时候也不要用重命名的名字,因为重命名在自引用之后,为什么呢,因为自引用是结构体声明的时候就要引用这个结构了,而重命名是在成员都声明完后才重命名,所以如果是重命名结构体想要自引用的话正确代码如下
cpp
struct node
{
char a[10];
int b;
char c[20];
struct node d;
}node;
2.结构体的内存对齐
在讲结构体的内存对齐之前,我们先来看一个代码来引出这个概念,代码如下
cpp
#include <stdio.h>
struct node
{
char a;
int b;
char c;
};
int main()
{
printf("%zd", sizeof(struct node));
return 0;
}
这个代码会输出什么呢,按照我们先前所学的只是来推理的话,char占一个字节,int占四个字节,这个结构体开了2个char类型以及1个int类型,那么就是2+4=6个字节,应该会输出6,那我们来运行一下看下会输出什么,如下图

我们可以发现输出竟然跟我们推理的输出不一样,那么就肯定是结构体开辟内存是跟正常开辟内存是有区别的,这个区别便是结构体开辟时会遵循结构体内存对齐这一底层逻辑,接下来我们来讲讲结构体的内存对齐
2.1.对齐规则
1.结构体的第一个成员变量对齐到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对齐到 偏移量 为 对齐数 的整数倍的地址处
对齐数:编译器默认的一个对齐数 与 该成员变量大小的较小值
VS中默认对齐数是 8
Linux中gcc没有默认对齐数,对齐数就是成员变量自身大小
3.结构体总大小为最大对齐数(结构体中每个成员中最大的对齐数)的整数倍
4.如果嵌套了结构体的情况,结构体内嵌套的结构体的内存分配就跟前面一样分配,结构体整体的大小就是所有成员的对齐数中的最大对齐数的整数倍(对齐数包含嵌套的结构体内的成员)
那么,结构体的对齐规则我们就讲完了,我们通过分析代码来辅助理解上面的这些规则,我们先用先前提过的代码来分析,我们把代码重新拷下来,如下
cpp
#include <stdio.h>
struct node
{
char a;
int b;
char c;
};
int main()
{
printf("%zd", sizeof(struct node));
return 0;
}
我们通过图文来解析这个代码,首先如果要创建一个node结构体的话肯定是需要一个空间的,那么既然需要空间,那么自然是肯定有首地址的,那么我们看下图,假设创这个结构体的话首地址是箭头所指的地址

那么,接下来是第一个成员,因为一开始偏移量是0,所以直接开辟char类型的字节就可以了,那么就是开辟1个字节的空间,开辟完后如下图

接下来就是剩余成员的内存开辟了,我们来看第二个,是int类型,那么这个类型的对齐数就是min(4,8),也就是4,那么我们要先找到一个偏移量是4的整数倍的地址,我们从char往后找,可以发现下图蓝色箭头所指的地址偏移量就是4,找到地址后再分配 4个字节给这个成员,如下图

接下来就是最后一个成员了,是char类型的,那么这个类型的对齐数就是min(1,8),也就是1,那么,就是找到偏移量是1的倍数的地址,我们知道所有正整数都是1的倍数 ,所以这都不用找就知道第三个成员内存要给他怎么分配了,如下图

那么,现在成员的内存已经分配好了,这个结构体的内存具体是多大呢,这就是最后一步了,我们要找到成员里最大的对齐数,这个结构体的话就是int,也就是4,结构体的大小就是最大对齐数的整数倍,现在这个结构体的内存是9,那么既然要是4的整数倍,自然就是12了,所以这个结构体的内存分配其实是这样的,如下图

我们可以发现,上面创建结构体的时候,有6个字节是没放东西的,那么,这些内存就浪费掉了,那么,同样的成员,怎么做可以让结构体内存尽可能的少损耗呢,其实是有办法的,就是数据类型所占字节小的放前面,大的放后面,这样就可以节省内存了
我们来优化下上面的结构体
优化:如下代码
cpp
#include <stdio.h>
struct node
{
char a;
char c;
int b;
};
int main()
{
printf("%zd", sizeof(struct node));
return 0;
}
这个代码相比上面的代码,我们只是将结构体内的成员的位置换了换,但是对于内存来说,那可是节省了很多空间,我们来看这个结构体会分配的内存是多少,如下图

我们可以发现,开辟的内存是8个字节,相比先前的结构体而言少了4个字节,这可是整整少了三分之一,对于成员很多的结构体而言便是大优化了,那么,我们来看一下运行的结果是不是8呢,如下图

结构体嵌套结构体的分配空间
那么,接下来我们也来模拟下结构体嵌套结构体的情况下是怎么分配空间的,就以下面这个代码为例吧
cpp
#include <stdio.h>
struct node
{
char a;
char c;
int b;
};
struct pr
{
char a;
int b;
char c;
struct node d;
};
int main()
{
printf("%zd", sizeof(struct pr));
return 0;
}
首先node结构体我们先前已经讲过了,他的内存分配空间是这样的,如下图

那么,既然嵌套的结构体已经知道内存是多大了,那我们只需要把这个结构体当成一块空间就可以了,那么我们先把嵌套结构体前的成员先开辟好,然后再来讲这个结构体,如下图

根据我们先前学的知识,pr的a,b,c成员已经开辟好了,接下来就是开辟结构体空间的问题了
这里就有个歧义了,开辟的结构体的首地址是哪里,是直接接在后面呢,还是什么呢,那么这里就直接强调一下,被嵌套的结构体成员不是简单接在前一个成员的下一字节,而是偏移量需要是嵌套结构体自身的最大对齐数的整数倍
对于这个被嵌套的结构体来说,那毋庸置疑就是4了,所以给结构体开辟完内存后便是如下图

那么整个结构体所占内存是多少呢,那便是这个结构体所有对齐数的最大对齐数的整数倍,这个结构体的最大对齐数就是4,其实内存是20个字节,刚好满足最大对齐数的倍数,所以就不用往后开辟空间了,那么我们来看看这个代码运行的结果是不是跑出来20,如下图

2.2.为什么存在内存对齐
讲完了内存对齐的原理后,那么为什么要内存对齐呢,直接一个一个放下去有什么问题呢 ,这里就来讲讲为什么存在内存对齐,主要是有2个原因
1.平台原因
不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处取特定类型的数据,否则会硬件异常
2. 性能原因(主要)
我觉得这个原因反而是主要的原因,因为对于未对齐的内存,处理器需要作俩次内存访问,但是对齐的内存访问只需要进行一次访问
我们来解释一下第二点的原因,首先我们需要知道对于处理器而言,一个处理器总是会从内存中取固定的字节,那么,我们通过图文讲解来辅助理解,依旧是先前的图,我们假设处理器是每次取4个字节,对齐后的内存分布如下图,绿色线就是处理器每次取的字节

处理器每次访问的时候都可以一次就完美的得到对应的成员数据,但是如果我们不内存对齐的话,得到的就是如下图

我们可以发现,如果不对齐的话,那么处理器如果要整型类型的数据的话继续要取俩次字节
那么同理,如果内存不对齐的话,对象是很可能分放在俩个不同内存块中的(这个俩个内存块指的是处理器每次访问的内存块 )
所以,总的来说,结构体的内存对齐就是为了用空间换时间
2.3.修改默认对齐数
我们已经知道了VS的默认对齐数是8,那么可以更改这个默认对齐数吗,是可以的
存在一个预处理指令,可以改变编译器的默认对齐数
#pragma
这个预处理指令怎么用呢,很简单,我写俩个代码你们看下就会用了
cpp
#pragma pack(1)
#pragma pack()
第一行是将编译器的默认对齐数改为1,第二行是将编译器的默认对齐数修改为初始的默认对齐数
注 :一般对齐数是调整为2的整数次大小,因为别的大小的对齐数没什么大意义
Linux系统中不能用这个pragma预处理指令,因为Linux系统没有默认对齐数
3.结构体传参
结构体传参分俩种一种是直接传结构体变量名,一种是传结构体变量的指针,我们来看看这俩种
第一种:直接传值
cpp
#include <stdio.h>
struct node
{
char a;
char c;
int b;
};
typedef struct pr
{
char a;
int b;
char c;
struct node d;
}pr;
void solve(pr x)
{
printf("%d", x.b);
}
int main()
{
pr t = { .b = 10 };
solve(t);
return 0;
}
第二种:传地址
cpp
#include <stdio.h>
struct node
{
char a;
char c;
int b;
};
typedef struct pr
{
char a;
int b;
char c;
struct node d;
}pr;
void solve(pr* x)
{
printf("%d", x->b);
}
int main()
{
pr t = { .b = 10 };
solve(&t);
return 0;
}
因为传参很简单,这里就不多赘述了
接下来我们来分析分析这俩种传参哪种好
其实是第二种(即传地址 )更好,学过函数栈帧开辟与销毁的都知道如果是直接传结构体过去的话,那就再开辟一块空间当作形参,那么如果结构体很大的话,就会很浪费内存,但第二种传地址过去就不会有很多的内存浪费,因为是直接通过指针改变在原结构体处进行操作
所以,在结构体传参的时候,最好传结构体的地址
4.结构体实现位段
结构体讲完后我们来讲讲只有结构体能实现的功能 ,那就是位段
4.1.什么是位段
位段就是按比特位的形式分配内存
在C99环境前,位段的成员必须是int,unsigned int或者signed int,但是到了C99环境后,位段的成员进行了优化,就是说位段的成员还可以是short类型,也可以是char类型等等
位段的使用方式就是常规创建完变量后,在后面接一个冒号和一个数字。数字表示的就是给这个变量分配多少bit的空间****, 那么,我们来使用下位段,代码如下
cpp
struct node
{
int a:2;
int b:5;
int c:10;
int d:29;
};
这个结构体中的所有成员就都是位段类型,a是占2个bit,b是占5个bit,c是占10个bit,d是占29个bit
注 :在一个结构体内创建位段类型的时候,最好要保证创建的位段类型是一样的,不然编译器开辟的空间就会很玄妙了,无从分析,我尝试了下在VS里一个结构体内开辟不同类型的位段,最后结构体所占的空间分析不出来
4.2.位段的内存分配
对于上面的那个结构体,他的内存是多大呢,我们来看一看,所占内存如下,是8个字节

首先,我们现在分析的是VS的位段的内存分配,因为位段在每个编译器里其实是不一样的,所以这里还是要强调一下
因为int的bit有点多,那么我们用char来分析一下,就用下面这个结构体的内存来分析
cpp
struct node
{
char a:3;
char b:4;
char c:2;
char d:1;
};
我们通过图文讲解来加深理解,假设首地址在这里,然后下面这个图一个格子是一个bit位的大小,那么一个char类型就是8个字节,所以先把char划分完,如下图划线

接下来就是第一个位段类型的变量a,他占三个bit位,在VS中,位段成员的内存是从右向左分配的,然后如果剩余的位无法容纳下一个位段成员的内存的时候,是会舍弃,然后开辟新的空间的,知道这个后,那么第一个a的3个bit开辟在哪就知道了(先开辟一个char类型大小的空间,然后从右往左填充),如下图

接下来第二个位段成员是b,占了四个bit位,因为剩余的空间还有五个bit位,足够塞了,所以可以接着往里塞,如下图

接下来第三个位段成员是c,占了俩个bit位,剩余的空间不够了,所以要开辟一个新的空间来存放,第四个位段成员你们应该也已经会了,所以全部放完后如下图

那么这个结构体开辟的空间就是2个字节,我们来看一下运行的结果是不是2,确实如我们推理的一般,如下图

那么到此,位段的内存分配就讲完了
注:位段涉及很多不确定因素,位段是不支持跨平台的,所以如果是做可移植的程序的话就要尽量避免使用位段
4.3.为什么位段不支持跨平台
我们在上面的注里讲了为什么位段不支持跨平台,其实主要有几个原因
1.如果我们用的是int之类的位段,没有加上unsigned或者signed,那么这个int是有符号数还是无符号数是不确定的,最明显的就是char,char我们先前就提过,char的有无符号取决于编译器
2.位段中最大位的数目我们无法确定,就以long为例,有的编译器是占4个字节,有的编译器是占8个字节,那么,我long a:40;这么一个位段,对于4个字节的而言就是存不下的,但是对于8个字节的而言是可以存下的
3.位段中的成员在内存中是从左向右分配还是从右向左分配是尚未定义的,虽然在VS中是从左向右分配的,但是别的编译器是可能从右向左分配的
4.当一个结构体中包含了多个位段成员,那么当有剩余空间的时候,如果下一个位段成员放不下,VS是会开辟一个新空间,但是有点编译器是会把剩余空间用完后再开辟新空间,所以剩余空间的使用这也是不确定的
跟结构体相比,位段可以达到同样的效果,并且可以更好的节省空间,唯一的缺点就是有跨平台的问题
4.4.位段的应用
那么学完位段后,我们来讲讲位段的应用场景,位段的应用现在讲其实有点超纲了,所以这里就简单提一下,我们可以用位段来存储IP数据报格式中的属性,这样可以节省很多内存
下图是网络协议中,IP数据报的格式

我们可以发现每一行都是32个字节,那么就可以用int的位段来节省内存,因为如果你要使用类型的话,那就很麻烦了,搞清楚每个需要用的数据类型是关键,问题是搞清了每个需要用的数据类型依旧会造成内存浪费,为什么呢,因为3位以及13位是肯定会造成内存浪费的,但是如果用位段的话就没有这个问题了
每次传输数据的时候内存花的少了,那么自然单次能传输的数据就多了,这也可以相当于是网络上你们是用社交平台发消息给对方,优化了内存就可以使得在同一时间内,能传输数据的人就更多了
4.5.位段使用时的注意事项
因为一个位段成员的内存是按bit来计量的,但是在内存中地址是按字节来递增的,所以位段就不可以使用跟地址有关的操作,比如取地址,那自然不能用scanf直接输入位段成员,因为scanf也是通过地址来进行输入
cpp
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
int main()
{
struct A sa = { 0 };
scanf("%d", &sa._b);//这是错误的
//正确的⽰范
int b = 0;
scanf("%d", &b);
sa._b = b;
return 0;
}
那么到此,结构体部分的内容就讲解完毕啦
联合体
学完了结构体之后,接下来学习联合体就很简单了。
1.联合体类型的声明
其实我们会了结构体类型的声明后,其实也就会了联合体类型的声明,只需要将struct改成union就可以了,union是联合体的关键字,这里就不再讲了
那么结构体和联合体的区别是什么呢
结构体:为每一个成员分配各自的空间
联合体:只为最大的成员分配足够的内存空间
联合体的特点是所有成员共用同一块内存空间,所以联合体也被称为:共用体
那么既然联合体的所以成员是共用一块内存空间的,那么自然只要对其中一个成员赋值,其他成员的值也会受到影响
2.联合体的特点
联合体的成员因为是共用同一块内存空间的,那么联合体的大小至少是最大成员的大小,注意,是至少,是可能比最大成员的大小大的
联合体的特性其实和 结构体是差不多的,也就是说 联合体也是有 内存对齐的,原则也跟结构体一样,所以在内存分配中,其实联合体的每个成员的首地址都是一样的 ,然后,因为最后联合体的大小要满足最大对齐数的整数倍,所以联合体的大小是可以比最大成员所占内存大的,我们用下面这个代码来举例
cpp
union node
{
char a[5];
int b;
};
int main()
{
printf("%zd", sizeof(union node));
return 0;
}
虽然这个联合体中最大成员的大小是5个字节,但是要对齐最大对齐数,所以联合体的大小就是8,如下图

附:因为我们知道了联合体和结构体是差不多的,这里拓展一下 ,联合体也可以位段,但为什么我在结构体里说只有结构体能位段呢,因为联合体位段其实没什么意义,主要是联合体嵌套位段的结构体
3.联合体大小的计算
在第二点的部分我已经将联合体大小怎么计算已经讲过了,但是还是要强调一下,所以再强调一下
1.联合体的大小至少是最大成员的大小
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
4.联合体的应用
场景一:礼品兑换单中有三种商品,每一种商品都有:库存量,价格,商品类型这三个信息,还有他们自己的信息
图书:书名,作者,页数
杯子:设计
衬衫:涉及,颜色,尺寸
当我们看到这个场景的时候,最简单粗暴的方法就是直接一个结构体粗暴搞定,代码如下
cpp
struct gift
{
//公共属性
int sum;
double price;
int type;
//特殊属性
char name[30];
char writer[20];
int page;
char design[20];
char color[10];
int size;
};
但是每次只是录入一种商品的信息,如果用结构体的话就会很浪费空间,这时就可以用联合体来优化,达到节省空间的目的,优化后的代码如下
cpp
struct gift
{
//公共属性
int sum;
double price;
int type;
//特殊属性
union
{
struct
{
char name[30];
char writer[20];
int page;
}book;
struct
{
char design[20];
}cup;
struct
{
char design[20];
char color[10];
int size;
}shirt;
}one;
};
通过联合体的使用,特殊属性的三中商品就相当于是存在了一个空间里,虽然改了一个结构体,别的结构体的元素也会发生变化,但是别的元素变化并不影响我们这次的商品兑换
场景二:写一个程序,判断当前机器是大端还是小端
这题先前我们在讲数据在内存中存储部分的时候我们是通过指针来实现的,那么这个其实也可以通过联合体来实现,我们只需要开一个int和char俩个成员的联合体,因为共用一个空间,那么就改int成员的值改为1,如果char成员值变了就说明是小端,如果没变就是大端,我们直接来看代码
cpp
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;//返回1是⼩端,返回0是⼤端
}
那么,到此,联合体部分的内容也就讲完啦
枚举
1.枚举类型的声明
枚举顾名思义就是一一列举(把可能的取值一一列举)
就比如我们现实生活中,周一到周日可以列举,性别可以列举,月份可以列举,只要是有意义的,都可以列举
枚举的关键字就是enum
然后枚举与结构体和联合体的差异是,枚举里的枚举常量是用,隔开的
cpp
enum Color//颜⾊
{
RED,
GREEN,
BLUE
};
上述代码定义的enum Color就是枚举类型,{}中的内容就是枚举类型的可能取值,也叫枚举常量,既然是常量了,自然在使用的时候是不可以进行赋值的 ,当然在声明的时候可以赋初值,如下代码
cpp
enum Color//颜⾊
{
RED=2,
GREEN=4,
BLUE=8
};
那么,不赋初值的话,RED,GREEN,BLUE这些枚举常量是多少呢,那便是从0开始,往后依次递增1,也就是RED为0,GREEN为1,BLUE为2
·也有有些赋初值,有些不赋初值的情况,如下代码
cpp
enum Color//颜⾊
{
RED=2,
GREEN,
BLUE=8
};
这个代码里,就是RED为2,GREEN为3(因为没赋初值所以就是前面一个枚举常量的值加1),BLUE为8
2.枚举类型的优点
那么此时有人会想了 ,我们可以用#define来定义常量,为什么要使用枚举呢,那自然是各有好处的,我们来讲讲枚举的好处
1.如果需要定义的常量多的话,使用枚举就会很方便了,可以一次定义多个常量
2.#define a b,是直接将a替换成b,并不会检查,但是枚举有类型检查,更加严谨
3.增加了代码的可读性和可维护性(就以先前指针部分实现的计算机为例,那时我们用switch时候直接case1,2,3,4,但是1,2,3,4具体实现的功能我们还要看,但是我们可以用枚举来优化变成case Add,case Mul等等)
4.便于调试,如果是#define的话,在预处理阶段就全部替换好了
5.枚举常量是遵循作用域规划的,如果枚举是生命在函数内部的,那就只能在函数内部使用
3.枚举类型的使用
cpp
enum Color//颜⾊
{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值
那是否可以拿整数给枚举变量赋值呢?在C语言中是可以的,但是在C++是不行的,C++的类型检查比较严格。
结语:
希望以上内容对你有所帮助,感谢观看,若觉得写的还可以,可以分享给朋友一起来看哦,毕竟一起进步更有动力嘛
