枚举(enum)是C语言的一种特殊类型。当我们在编程中遇到定义一些固定长度或范围的数值时,可以考虑使用枚举类型。使用枚举可以让我们的程序可读性更强、看起来更加直观。举个例子,如果我们在编程中需要使用数字0~6分别表示星期日~星期六,程序的可读性就不高,我们需要翻手册或者看程序注释才能知道每个数字具体代表什么意思。如果我们使用枚举呢,基本上不需要看注释或手册就可知晓其大意。

enum week    // enum 枚举类型{枚举值列表};
{SUN,MON,TUE,WED,THU,FRI,SAT,
};
enum week today = SUN; //使用枚举类型定义一个变量

使用enum定义的枚举值列表中,默认值是从0开始,然后依次递增:SUN=0,MON=1...。当然我们也可以显式指定枚举值:

enum week
{SUN = 1,MON,TUE,WED,THU = 7,FRI,SAT,
};
//SUN=1,那么接下来MON=2,TUE=3,WED=4
//THU=7,那么接下来FRI=8,SAT=9

1. enum经常使用的三种方法

使用枚举类型定义变量,使用方法跟结构体、共用体类似,经常使用的三种方法如下:

enum week //定义枚举类型的同时,定义枚举变量
{SUN,MON,TUE,WED,THU,FRI,SAT,
}today, tomorrow;
​
enum //可以省去枚举类型名,直接定义变量
{SUN,MON,TUE,WED,THU,FRI,SAT,
}today, tomorrow;
​
enum week //先定义枚举类型,再定义枚举变量
{SUN,MON,TUE,WED,THU,FRI,SAT,
};
enum week today, tomorrow;

2. 枚举的本质

在C语言中,枚举是一种类型,属于整型的范畴,使用enum定义的枚举值列表,其实就是从0开始的一系列整数序列。整型除了short、int、long、long long外,还包括char、_Bool(C99标准新增)和enum。因此,枚举的使用其实和整数值其实没啥区别:我们使用枚举类型定义的变量,同样可以作为函数参数、函数返回值、用来定义数组、甚至和结构体混用等。

enum week get_week_time (void);
int set_week_time (enum week time_set);
int change_week_time (enum week *p);
enum week a[10];
struct student
{char name[20];int age;enum week birthday;
};

枚举有点类似于typedef,给一个数值添加一个别名,让我们的程序更加直观、可读性更高。枚举类型在本质上就是有命名的整数,属于整型的一种,在代码中是可以和整型互换的。

enum week t = SUN;
int  t2 = SUN;
enum week t3 = t2;
enum week t4 = 100;

在上面的代码中,枚举变量和整型变量相互赋值,都是可以正常编译和运行的。我们在代码中使用枚举类型,在最终编译生成的可执行文件中都会被整型数值代替。

enum week
{SUN = 5,MON,TUE,WED,THU,FRI,SAT,
};
​
int main (void)
{enum week today = THU;return 0;
}

在上面的示例代码中,我们定义了一个枚举类型week,然后定义了一个枚举变量today,并赋值为THU。反汇编上面的代码,我们可以看到汇编代码:

00010400 <main>:10400:   e52db004    push    {fp}        10404:   e28db000    add fp, sp, #010408:   e24dd00c    sub sp, sp, #121040c:   e3a03009    mov r3, #9  10410:   e50b3008    str r3, [fp, #-8]10414:   e3a03000    mov r3, #010418:   e1a00003    mov r0, r31041c:   e24bd000    sub sp, fp, #010420:   e49db004    pop {fp}        ;10424:   e12fff1e    bx  lr

在C程序中定义的枚举变量today,在汇编代码的第1040c处,我们可以看到:枚举值THU被替换为整型数值9。使用枚举的唯一好处就是增加代码的可读性,它的作用跟宏定义的作用有异曲同工之妙。

3. 枚举和宏

枚举与预处理指令#define的作用差不多,都是为了增加代码的可读性。但在实际使用中,两者还是有些差别的:宏在预处理阶段,通过简单的字符串替换就全部被替换掉了,编译器根本不知道有宏这么一个玩意;而枚举类型则在编译阶段全部替换为整型。

跟宏相比,枚举的优势是:枚举可以自动赋值,而宏则需要一个一个单独定义。因此,在自定义一些有规则的类型值的时候,使用枚举会更加方便。枚举可以自定义的变量值来代替数字值,使我们的程序代码有更高的可读性。

4. Linux内核中的枚举类型

在Linux内核代码中,充斥着大量的枚举类型数据,有些枚举类型的定义看起来很奇怪,比如:

enum
{MM_FILEPAGES,MM_ANONPAGES,MM_SWAPENTS,NR_MM_COUNTERS
};
enum pid_type
{PIDTYPE_PID,PIDTYPE_PGID,PIDTYPE_SID,PIDTYPE_MAX
};

Linux内核中使用enum定义的枚举类型大部分是没有枚举名的,而且通常会在一串枚举值之后带上一个NR*的元素用来表示枚举值的数量。当我们不需要使用枚举类型去定义一个枚举变量时,枚举并不需要一个名字,这些无名的枚举类型其实就相当于宏定义。而最后一个元素NR或MAX,一般可以用来记载枚举列表中元素的个数,或者作为循环判断的边界值。

5. 使用枚举需要注意的地方

什么是类型?类型是一定范围的数值及方法的集合。枚举作为整型类型的一种,在编程使用过程中,也有一些注意的地方,比如作用域。使用枚举定义的常量也遵循数据作用域规:包括文件作用域、代码块作用域等,在同一个作用域能不能出现重名的枚举常量名。

enum week1
{SUN,MON,TUE,WED,THU,FRI,SAT,
};
enum week2
{SAT,UNKNOW,
};
int main (void)
{   return 0;
}

在上面的代码中,我们定义了两个枚举类型,其中枚举常量SAT重名,编译时就会发生如下错误:

error: redeclaration of enumerator `SAT'
error: previous definition of 'SAT' was here

出现错误的原因是,我们定义的不同枚举类型中的两个枚举常量名同在一个作用域:文件作用域,我们稍微改一下代码就可以避免冲突:

#include <stdio.h>
enum week1
{SUN,MON,TUE,WED,THU,FRI,SAT,
};
int main (void)
{printf("%d\n", SAT);enum week2{SAT,UNKNOW,};printf("%d\n", SAT);    return 0;
}

我们将枚举类型week2的定义放到了main函数内,week2的作用域就从文件作用域变为代码块作用域。这个时候,两个枚举类型中的同名枚举常量就不会再发生冲突,程序的运行结果为:

6
0

跟涛哥一起学嵌入式 30:C语言枚举类型深入剖析相关推荐

  1. 跟涛哥一起学嵌入式 第02集:工作还是考研?

    大家好,我是涛哥,今天我们聊聊第一个话题:工作还是考研. 工作与考研,是每个大三大四学生都要去纠结一下的问题,也是一个很难做抉择的话题.对自己的现状不满意,蹉跎了岁月,感觉自己学得不够多,没学到什么技 ...

  2. 跟涛哥一起学嵌入式 25:我接触过近50块嵌入式开发板,分享一下教训和总结...

    最近老是有学员问我:涛哥,你的嵌入式教程针对哪款开发板鸭?到底使用哪款开发板学习?我的回答往往是:暂时不用开发板,学习嵌入式,不一定非得用开发板,在qemu仿真平台上学习就可以了.3年前我发布了互联网 ...

  3. 跟涛哥一起学嵌入式 第06集:后ARM时代,嵌入式工程师的自我修养

    大家好,我是涛哥,今天我们继续聊一聊嵌入式的学习,由于最近比较忙,就把以前写的一篇文章重新发给大家,里面谈到的一些学习方法和学习经验,还是很值得参考一下的. 嵌入式学习的一些概念理解误区 很多嵌入式初 ...

  4. 跟涛哥一起学嵌入式 20:后ARM时代,嵌入式工程师的自我修养

    1 嵌入式学习的一些概念理解误区 很多嵌入式初学者认为,学嵌入式,就是学习ARM,就是学习开发板.买一块开发板,然后在上面"移植"u-boot.Linux内核,再使用busybox ...

  5. 跟涛哥一起学嵌入式 31:深入浅出CPU流水线工作原理

    现在的CPU处理器一般都是超流水线工作,动不动就是10级以上流水线,超高主频,这两者之间有什么关系呢?今天就跟大家科普下CPU流水线的工作原理,以及他们之间的关系. 说到流水线,很多人会想到富士康:说 ...

  6. 跟涛哥一起学嵌入式 26:深入浅出计算机编码、乱码问题

    很多新手在编写程序.使用软件打开文档或者浏览网页时,经常遇到乱码显示.全角半角的问题. 网上也有很多解决的方法,大部分都是跟编码有关:比如Unicode.UTF-8.ASCII码.GB2312..., ...

  7. 跟涛哥一起学嵌入式 16:设计一款CPU芯片到底有多难?

    文章结构 导读 一颗芯片是怎么诞生的? 一款CPU是如何设计出来的? 设计一款CPU到底难在哪里? 导读 这几天,刷遍朋友圈的新闻就是:中兴被"一剑封喉",被美国停止一切芯片进口和 ...

  8. 跟涛哥一起学嵌入式10:关于校招,应届生都应该看一看

    金九银十,是应届生求职的黄金时期.每年这个时候,各大企业.名企一般都会到校园去做各种宣讲.面试招聘.对于大部分应届生来说,通过校园招聘渠道,找到一份靠谱工作的概率远远胜过社会招聘.然而很多应届生却对校 ...

  9. 跟涛哥一起学嵌入式 第10集:关于校招,应届生都应该看一看

    金九银十,是应届生求职的黄金时期.每年这个时候,各大企业.名企一般都会到校园去做各种宣讲.面试招聘.对于大部分应届生来说,通过校园招聘渠道,找到一份靠谱工作的概率远远胜过社会招聘.然而很多应届生却对校 ...

最新文章

  1. 如何进行app的兼容性测试?需要考虑哪些方面?
  2. python调用其他文件的类和函数
  3. python redis模块_python redis 模块 官方文档(中)
  4. 第三次spring冲刺1
  5. 156 13.67用matlab答案,MATLAB习题答案
  6. 英语学习笔记2019-10-11
  7. Windows Phone 7 利用计时器DispatcherTimer创建时钟
  8. css top 定位百分比,css 使用relative设置top为百分比值的方法(仿百度首页)
  9. 20191001每日一句
  10. win11 22H2任务栏一条白线如何消除?
  11. 公务员计算机职称有哪些,2017职称考试有哪些
  12. HrbustOJ 1167 每种面值的货币要多少
  13. python Flask 编写 api 接口,CORS 解决 flask 跨域问题
  14. Tcp/ip协议 详解
  15. 微信开发者工具创建vue项目步骤
  16. 麦芽糖-刀豆球蛋白A,maltose-ConcanavalinA,刀豆球蛋白A-PEG-麦芽糖
  17. 鬼影没干掉。 病毒已经清除。
  18. 【Vuejs】1454- 深入了解 vue-cli
  19. 《唐伯虎点秋香》中的超级对联
  20. 红绿3d眼镜与红蓝3d眼镜区别_Rokid X 非白三维,AR眼镜 + 3D扫描

热门文章

  1. App换量攻略|实操技巧+换量神器,app换量推广
  2. 如何在一天内为你的实验室做一个网站
  3. Live800:新的消费趋势下,企业在线客服需哪些改变?
  4. 《OPPO安全——安全与隐私小课堂》之 日防夜防,“隐私窃贼“难防?手把手教你如何使用OPPO手机管理应用权限
  5. HTML5基础入门教程
  6. Jquery中ul li循环取值方式
  7. nuxt 移动端适配
  8. 选择排序(二)——希尔排序
  9. 普通人的普通生活真的不普通
  10. 验证码信息验证(不区分大小写)