本文主要是介绍扒一枚举这个怪胎,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
人生若只如初见:初识枚举
第一次见到枚举,大家都会觉得很简单,很多资料都会告诉你,
枚举是C语言中的一种基本数据类型,
它由关键字enum+枚举类型标识名(标识符,自定义)+{枚举成员名1,枚举成员名2,枚举成员名3,枚举成员名4 }
enum Frame{cmd1=01,cmd2,stu1,stu2,};printf("输出枚举成员stu2的值%d\n",stu2);printf("输出枚举成员stu1的值%d\n",stu1);printf("输出枚举成员cmd2的值%d\n",cmd2);printf("输出枚举成员cmd1的值%d\n",cmd1);
输出的结果是:
1:枚举成员的特性(再识枚举,其实它也有自己的小脾气)
也就是说,枚举成员=只能是整形,且只能是常量,以下几种情况都是对枚举成员的错误赋值
(一):枚举成员定义成字符串
,我们试一试将枚举成员cmd1设置为字符串cmd1="a",可以看到编译阶段直接报错。注意看cmd2='a',因为C语言中将字符型等价于整形(具体参考ASCIL码),是符合枚举成员的赋值策略的,这一点需要注意。
(二):枚举成员定义为整形变量
我们试一试将枚举成员定义成变量,看看结果如何。
编译直接报错
(三):枚举成员定义为实形常量
编译就报错,这里还有一个点需要注意,就是大量的资料里都将enum和预定义命令#define作比较。认为二者在功能实现上有相似之处。通过上面的例子可以看出。
#define stu1 1.2 是合法预定义指令
enum Frame{stu1=1.2} ;是不合法语句,需特别注意
总结:枚举成员具有在赋值上,具有如下属性
1:必须是常量,必须是整形常量(整形常量和合法ASCIL字符都可以),且是默认为是有符号整形常量。
2:枚举有自赋值属性和自增属性,且看如下属性
1:如果定义枚举类型时,如果不对枚举成员赋值,则从左起第一个枚举成员默认为0
2:枚举成员第一个值赋值后,从左往右,枚举成员的值依次+1
1:举例说明
#include <stdio.h>
#include <stdlib.h>int main()
{ int a =10;enum Frame{stu1,stu2,cmd1,cmd2};printf("输出枚举成员stu1的值%d\n",stu1);printf("输出枚举成员stu2的值%d\n",stu2);printf("输出枚举成员cmd1的值%d\n",cmd1);printf("输出枚举成员cmd2的值%d\n",cmd2);return 0;}
2:举例说明
#include <stdio.h>
#include <stdlib.h>int main()
{ int a =10;enum Frame{stu1=-3,stu2,cmd1,cmd2};printf("输出枚举成员stu1的值%d\n",stu1);printf("输出枚举成员stu2的值%d\n",stu2);printf("输出枚举成员cmd1的值%d\n",cmd1);printf("输出枚举成员cmd2的值%d\n",cmd2);return 0;
输出结果如上图
这里需要注意一点,枚举成员是可以赋值负数的,但是如果执行如下代码,定义一个unsigned char变量a,再把stu1,赋值给a,编译运行后就会出现错误。这里涉及到负数以补码的形式存储,和C语言隐形转换的知识,这里不细讲!有时间可以,另外写单独写。
int main()
{ unsigned char a =10;enum Frame{stu1=-3,stu2,cmd1,cmd2};a = stu1;printf("输出枚举成员stu1的值%d\n",stu1);printf("输出枚举成员stu2的值%d\n",stu2);printf("输出枚举成员cmd1的值%d\n",cmd1);printf("输出枚举成员cmd2的值%d\n",cmd2);printf("输出a的值%d\n",a);return 0;}
3:枚举成员,也是可以独立赋值
#include <stdio.h>
#include <stdlib.h>int main()
{ unsigned char a =10;enum Frame{stu1=-3,stu2='a',cmd1=9,cmd2=1};//char b =(char) a;a = stu1;printf("输出枚举成员stu1的值%d\n",stu1);printf("输出枚举成员stu2的值%d\n",stu2);printf("输出枚举成员cmd1的值%d\n",cmd1);printf("输出枚举成员cmd2的值%d\n",cmd2);printf("输出b的值%d\n",a);return 0;
可以看出,如果存在必要,可以单独对枚举成员单独赋值,只是情况非常少见。
聊聊enum的两个表亲
2.1:聊聊enum 的表亲 #defined
#define a1 3
enum{a2=3};
两者实现的功能是相同的。但是enum和#define是表亲关系,就像你和你姑姑家的表弟。血缘关系还要往上两代,所以它们之间有共同点,但是不多!在实际应用中,没有谁更好用,谁的优点更明显,只有根据项目需求合理应用。
#define a1 "a1" //替代字符串#define a3(y) y*y //带参数宏代替
#define a4 3.14159 //a4代替实形常量
#define a5 a4 //宏定义的嵌套
#ifndef a6 //
#define a6 8
//等等
以上都是枚举无法执行的操作,切记枚举成员只能是整形常量。
2.2:enum 的另外一个表亲struct
如果说#define是和enum是性格(理解为作用有相似之处),那enum的另外一个表亲struct就只是和和enum长得有点像罢了(理解成代码书写方式),实际上,他们之间的区别还是很大的。
typedef enum SexMessage
{female=1,male}
BoyOrgirl;
BoyOrgirl enum1_SexMessage=female;typedef struct MessageOfClass //班级信息
{ int age; //年级float Height; //身高int sex; //性别char name[20]; //姓名
} studentmessage;studentmessage struct1_student1 = {20 ,15.8,female,"zhangsan"};
注意观察以上代码!我们声明和定义声明了一个枚举类型,定义了性别信息。定义声明了一个枚举变量,并赋值给这个枚举变量。定义声明了一个结构体类型, MessageOfClass //班级信息,并定义了一个结构体变量,赋值了结构体变量。
用来你就能理解为什么我说struct是也是enum的表亲了。
1:首先它们都能使用typedef(类型重定义)指令,指令格式typedef +(结构体or枚举)+重定义类型名
2:它们都能声明变量,枚举能声明枚举变量BoyOrgirl enum1_SexMessage;结构体能声明结构体变量,studentmessage struct1_student1
注意:声明的结构体变量,和声明枚举变量,它们在结构,赋值方式,占用内存大小方面都有很大不同:
枚举变量一次只能赋一个值,最好是使用已定义枚举类型里面的枚举成员
BoyOrgirl enum1_SexMessage=female;
如果结构体变量想赋其他值,如:”BoyOrgirl enum1_SexMessage=100;一般情况下,编译器也不会报错,但是最严谨的写法应该加上一个强制转换BoyOrgirl enum1_SexMessage=(enum SexMessage)100
我们来试一试
#include <stdio.h>
#include <stdlib.h>
#define pi 3.14159
#define pi2 pi
typedef enum SexMessage
{female=1,male}
BoyOrgirl;
BoyOrgirl enum1_SexMessage=(enum SexMessage)100;
int main()
{printf("输出枚举变量enum1_SexMessage的值%d\n",enum1_SexMessage);printf("输出枚举变量enum1_SexMessage的大小%d\n",sizeof(enum1_SexMessage)); //输出枚举变量的大小
}
输出结果是100。
再试试看看此时枚举变量的大小
此时我们再来填一个坑,就是我们已经知道了,枚举变量的大小是4Byte,我们试一下BoyOrgirl enum1_SexMessage=(enum SexMessage)0xFFFFFFFF;
#include <stdio.h>
#include <stdlib.h>
#define pi 3.14159
#define pi2 pi
typedef enum SexMessage
{female=1,male}
BoyOrgirl;
BoyOrgirl enum1_SexMessage=(enum SexMessage)0xFFFFFFFF;
int main()
{printf("输出枚举变量enum1_SexMessage的值%d\n",enum1_SexMessage);printf("输出枚举变量enum1_SexMessage的大小%d\n",sizeof(enum1_SexMessage)); //输出枚举变量的大小
}
看结果
发现到了吗?输出enum1_SexMessage=-1,结合之前我说枚举可以是负值的。我们就可以得出结论了:枚举变量4Byte的最高位是符号位。
这里仅看枚举变量最高字节,Byte4 = 0xFF ,展开为2进制 1111 1111 ,编译器识别最高位为1,判定为负数,负数需要转换为补码 (如果不知道具体转换方式,可百度)存储在RAM中,
存储的形式 (1000 0000、 0000 0000、 0000 0000、0000 0001)于是当我们再次取出该值时,将该值打印出来就是=-1;类比int型变量 能表示的范围(-0x7F FF FF FF-->+0x7F FF FF FF)枚举变量能正确表示的范围也是(-0x7F FF FF FF-->+0x7F FF FF FF)。
有兴趣的朋友,可以在去试试枚举成员 female的大小和能表示的范围大小。结论和结构体变量一致。都是4Byte ,表示范围是(-0x7F FF FF FF-->+0x7F FF FF FF)。
如果有极端情况下
你定义了一个枚举enum Enum2{a1,a2,............a9999999999999999999999}试想一下这样行不行。
再来看看,结构体
struct这个enum的老表,很多书籍和资料都说的比较透彻。我们可以自行查阅资料。
1:结构体类型在定义时,只对成员做类型说明,不能赋值。枚举只是做一个简单的替换,枚举里面的成员不做类型说明。成员赋值也不能理解为是C语句中的赋值,因为枚举定义时,实际上也是一种预处理命令,说人话就是他是给编译器看的,给编译器写的代码。
2:结构体变量才会占用内存,同样的枚举,也只是枚举变量才会占用内存,枚举定义时不占用内存
3:结构体可以嵌套结构体,而枚举不可以。且需要特别注意,实测发现结构体内,不能包含枚举
4:注意结构体变量和枚举变量的区别(主要指所占用空间的大小),结构体变量存在对齐原因。但是枚举变量固定为一个int的长度。
3.枚举在实际工程中的使用方法
枚举在实际工程中最常见的作用就是定义别名,类似于#define的作用。
如我们定义了一个监测温度的函数,函数根据温度放回一个状态,我们将状态分为如下几种
1)temperrature<-30℃时,返回verycool
2)-30℃<=temperrature<0℃,返回cool
3)0℃<=temperrature<25℃,warming
4)25℃<=temperrature<40℃ hot
5)25℃<=temperrature<50℃ very hot
首先,我们先定义一个函数原型,
由于我们放回的是字符串,由于C/C++中是没有返回值是字符串类型的函数,于是我们必须用数字代替。0代替verycool,1代替cool
如果使用#define verycool 1,要写5个很麻烦
这时就可以使用枚举了 enum TempureFlag{verycool,cool,warming,hot,veryhot};
函数类型,可以设施为
unsigned char Temperrature(void) //注意这里有个小坑,函数原型最好设置为int
{
int Tem;
scanf("%d\n",Tem);
if(Tem<-30)
return veaycool;
........................
}
最后一段代码,是我自己为了以后方面查看,大家可以忽略。
#include <stdio.h>
#include <stdlib.h>
#define pi 3.14159
#define pi2 pi
typedef enum SexMessage
{female=1,male}
BoyOrgirl;
BoyOrgirl enum1_SexMessage=(enum SexMessage)0xFFFFFFFF;typedef struct MessageOfClass //班级信息
{int age; //年级float Height; //身高int sex; //性别char name[20]; //姓名
} studentmessage;
studentmessage struct1_student1 = {20,15.8,female,"zhangsan"};int print_enum_function(void)
{printf("输出枚举成员female的地址%p\n",female);printf("输出枚举成员male的地址%p\n",male);//printf("输出枚举标识符SexMessage的地址%p",SexMessage);printf("输出枚举变量enum1_SexMessage的地址%p\n",&enum1_SexMessage);}int main()
{unsigned char a =10;typedef enum Frame {stu1=-3,stu2='a',cmd1=9,cmd2=1};//char b =(char) a;a = stu1;printf("输出枚举变量enum1_SexMessage的值%d\n",enum1_SexMessage);printf("输出枚举变量enum1_SexMessage的大小%d\n",sizeof(enum1_SexMessage));printf("输出枚举成员female的大小%d\n",sizeof(female));printf("输出常量立即数的大小%d\n",sizeof(0xFFFFFFFF));printf("输出枚举成员stu1的值%d\n",stu1);printf("输出枚举成员stu2的值%d\n",stu2);printf("输出枚举成员cmd1的值%d\n",cmd1);printf("输出枚举成员cmd2的值%d\n",cmd2);printf("输出b的值%d\n",a);printf("下一步调用print_enum_function函数\n");print_enum_function(); //即使是是形式参数是void类型的,在调用时也要写上()括号return 0;}
————————————————
这篇关于扒一枚举这个怪胎的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!