扒一枚举这个怪胎

阅读: 评论:0

扒一枚举这个怪胎

扒一枚举这个怪胎

人生若只如初见:初识枚举

      第一次见到枚举,大家都会觉得很简单,很多资料都会告诉你,

枚举是C语言中的一种基本数据类型,

它由关键字enum+枚举类型标识名(标识符,自定义)+{枚举成员名1,枚举成员名2,枚举成员名3,枚举成员名4 }

enum Frame{cmd1=01,cmd2,stu1,stu2,};printf("输出枚举成员stu2的值%dn",stu2);printf("输出枚举成员stu1的值%dn",stu1);printf("输出枚举成员cmd2的值%dn",cmd2);printf("输出枚举成员cmd1的值%dn",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的值%dn",stu1);printf("输出枚举成员stu2的值%dn",stu2);printf("输出枚举成员cmd1的值%dn",cmd1);printf("输出枚举成员cmd2的值%dn",cmd2);return 0;}

2:举例说明

#include <stdio.h>
#include <stdlib.h>int main()
{   int a =10;enum Frame{stu1=-3,stu2,cmd1,cmd2};printf("输出枚举成员stu1的值%dn",stu1);printf("输出枚举成员stu2的值%dn",stu2);printf("输出枚举成员cmd1的值%dn",cmd1);printf("输出枚举成员cmd2的值%dn",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的值%dn",stu1);printf("输出枚举成员stu2的值%dn",stu2);printf("输出枚举成员cmd1的值%dn",cmd1);printf("输出枚举成员cmd2的值%dn",cmd2);printf("输出a的值%dn",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的值%dn",stu1);printf("输出枚举成员stu2的值%dn",stu2);printf("输出枚举成员cmd1的值%dn",cmd1);printf("输出枚举成员cmd2的值%dn",cmd2);printf("输出b的值%dn",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的值%dn",enum1_SexMessage);printf("输出枚举变量enum1_SexMessage的大小%dn",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的值%dn",enum1_SexMessage);printf("输出枚举变量enum1_SexMessage的大小%dn",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("%dn",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的地址%pn",female);printf("输出枚举成员male的地址%pn",male);//printf("输出枚举标识符SexMessage的地址%p",SexMessage);printf("输出枚举变量enum1_SexMessage的地址%pn",&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的值%dn",enum1_SexMessage);printf("输出枚举变量enum1_SexMessage的大小%dn",sizeof(enum1_SexMessage));printf("输出枚举成员female的大小%dn",sizeof(female));printf("输出常量立即数的大小%dn",sizeof(0xFFFFFFFF));printf("输出枚举成员stu1的值%dn",stu1);printf("输出枚举成员stu2的值%dn",stu2);printf("输出枚举成员cmd1的值%dn",cmd1);printf("输出枚举成员cmd2的值%dn",cmd2);printf("输出b的值%dn",a);printf("下一步调用print_enum_function函数n");print_enum_function();     //即使是是形式参数是void类型的,在调用时也要写上()括号return 0;}


————————————————
 

本文发布于:2024-01-31 02:00:41,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170663764024528.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:怪胎
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23