ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
【78.1 typedef和#define和enum。】 typedef称为“类型定义”,#define称为“宏定义”,enum称为“枚举”。三者都有“一键替换”的能力,但是应用的侧重点各有不同。请看下面的例子,要写一个函数,把学生的分数分为3个等级,第1等级是“优”(范围:“优”>=90分),第2等级是“中”(范围:70分<=“中”<90分),第3等级是“差”(范围:“差”<70分),实现此算法的函数需要一个输入口和一个输出口,用来输入分数和输出判断结果,判断的结果用三个数字常量0,1,2来表示,0代表“优”,1代表“中”,2代表“差”。代码如下: unsigned char GetGrade(unsigned char u8Score) { if(u8Score<70) { return 2; //2代表“差” } else if(u8Score>=70&&u8Score<90) { return 1; //1代表“中” } else { return 0; //0代表“优” } } 上述代码没有添加任何“typedef,#define,enum”,是“素颜照”级别的原始代码。现在对上述代码做一些美容,加入“typedef,#define,enum”的元素,代码如下: \#define BAD\_MEDIUM 70 //宏定义。用BAD\_MEDIUM来表示“差”和“中”分数的分界线 \#define MEDIUM\_GOOD 90 //宏定义。用MEDIUM\_GOOD来表示“中”和“优”分数的分界线 typedef unsigned char u8; //用typedef为类型“unsigned char”增加一个名为“u8”的代言人 enum {GOOD = 0,MEDIUM,BAD}; //用enum把“0,1,2”三个常量转换为“GOOD,MEDIUM,BAD” u8 GetGrade(u8 u8Score) { if(u8Score<BAD\_MEDIUM) //等级分数分界线的判断 { return BAD; //BAD就是常量2,代表“差”。 } else if(u8Score>=BAD\_MEDIUM&&u8Score<MEDIUM\_GOOD) //等级分数分界线的判断 { return MEDIUM; //MEDIUM就是常量1,代表“中” } else { return GOOD; //GOOD就是常量0,代表“优” } } 代码赏析: 赏析片段一: \#define BAD\_MEDIUM 70 //宏定义。用BAD\_MEDIUM来表示“差”和“中”分数的分界线 \#define MEDIUM\_GOOD 90 //宏定义。用MEDIUM\_GOOD来表示“良”和“优”分数的分界线 这里,用宏定义#define来关联分界线判断的分数,给后续代码的升级维护带来了便捷,因为用户有可能会要求把“差”“中”“优”三者的分数线进行调整,这时直接更改70和90这个数值就可以实现分数线的调整。可见,宏定义#define经常用在涉及“分界线”判断的场合。 赏析片段二: typedef unsigned char u8; //用typedef为类型“unsigned char”增加一个名为“u8”的代言人 用类型定义typedef为类型“unsigned char”增加一个名为“u8”的代言人,u代表unsigned的u,8代表此类型占用8位,比如unsigned char就是占用8位的unsigned类型,所以用u8。如果是16位的unsigned类型就用u16,32位则用u32,这都是单片机界的常用命名习惯。上述代码用了类型定义,今后代码中凡是想定义一个unsigned char变量,都可以直接用u8来替代。这样有两个好处:第一个好处,u8的字符个数明显比unsigned char少,省了敲代码的力气。第二个好处,方便代码在各种不同硬件平台上的移植,因为不同的单片机不同的编译器对unsigned char,unsigned int,unsigned long翻译所得的结果是不一样的,比如,51单片机的unsigned int是占用16位的,而很多32位单片机的unsigned int是占用32位的,它们的16位则用unsigned short int类型,而不是unsigned int。 当我们用51单片机写代码的时候,可以如下类型定义: typedef unsigned char u8; typedef unsigned int u16; typedef unsigned long u32; 当我们用32位的单片机写代码的时候,可以如下类型定义: typedef unsigned char u8; typedef unsigned short int u16; typedef unsigned int u32; 这样,当我们想把51单片机的代码移到32位的单片机上时,只需要修改类型定义typedef这部分的代码,就可以快速做到代码在不同编译器平台上的类型兼容。 赏析片段三: enum {GOOD = 0,MEDIUM,BAD}; //用enum把“0,1,2”三个常量转换为“GOOD,MEDIUM,BAD” 用枚举enum把“0,1,2”三个常量转换为“GOOD,MEDIUM,BAD”英文单词,最大的好处就是方便代码的阅读和修改。再多补充一点枚举的基础知识,上述代码中,第一个英文单词GOOD,经过“GOOD = 0”这条初始化的语句后,等效于常量0,后面的MEDIUM和BAD则C编译器自动对它们进行“累加1”排序,所以MEDIUM和BAD分别为常量1,2,这是C语言的语法规则。枚举enum的应用侧重在某些涉及到“状态”的数据类型,但是也不绝对。 【78.2 enum和typedef的相结合。】 enum一旦搭载上typedef后,可以把各自的特性发挥得淋漓尽致,产生另外一种常见的用途,那就是“人造”数据类型的用途,这里的“人造”解读为“人为制造”之意。比如上述78.1的函数u8 GetGrade(u8 u8Score),输出接口接收的是u8类型,但是内部return返回的是枚举类型的“GOOD,MEDIUM,BAD”其中之一,而u8虽然也能接收和兼容常量“GOOD,MEDIUM,BAD”,但是总是感觉有点“类型不匹配”的“不适感”,如果想消除这点“不适感”,可以用enum和typedef相结合的办法,修改后代码如下: \#define BAD\_MEDIUM 70 //宏定义。用BAD\_MEDIUM来表示“差”和“中”分数的分界线 \#define MEDIUM\_GOOD 90 //宏定义。用MEDIUM\_GOOD来表示“良”和“优”分数的分界线 typedef unsigned char u8; //用typedef为类型“unsigned char”增加一个名为“u8”的代言人 typedef enum { GOOD = 0, MEDIUM, BAD } Grade; //通过typedef 和enum的相结合,“人造”出一个新的数据类型 Grade。 Grade GetGrade(u8 u8Score) //这里返回的类型是Grade,而“GOOD,MEDIUM,BAD”就是属于Grade { if(u8Score<BAD\_MEDIUM) //等级分数分界线的判断 { return BAD; //BAD就是常量2,代表“差”。 } else if(u8Score>=BAD\_MEDIUM&&u8Score<MEDIUM\_GOOD) //等级分数分界线的判断 { return MEDIUM; //MEDIUM就是常量1,代表“中” } else { return GOOD; //GOOD就是常量0,代表“优” } } 【78.3 例程练习和分析。】 为了熟悉typedef,#define,enum的用法,现在要写一个函数,把学生的分数分为3个等级,第1等级是“优”(范围:“优”>=90分),第2等级是“中”(范围:70分<=“中”<90分),第3等级是“差”(范围:“差”<70分),实现此算法的函数需要一个输入口和一个输出口,用来输入分数和输出判断结果,判断的结果用三个数字常量0,1,2来表示,0代表“优”,1代表“中”,2代表“差”。 /\*---C语言学习区域的开始。-----------------------------------------------\*/ \#define BAD\_MEDIUM 70 //宏定义。用BAD\_MEDIUM来表示“差”和“中”分数的分界线 \#define MEDIUM\_GOOD 90 //宏定义。用MEDIUM\_GOOD来表示“良”和“优”分数的分界线 typedef unsigned char u8; //用typedef为类型“unsigned char”增加一个名为“u8”的代言人 typedef enum { GOOD = 0, MEDIUM, BAD } Grade; //通过typedef 和enum的相结合,“人造”出一个新的数据类型 Grade。 Grade GetGrade(u8 u8Score); //函数声明 Grade a; //“人造”出Grade类型的变量a,用来接收函数的判断结果。 Grade b; //“人造”出Grade类型的变量b,用来接收函数的判断结果。 Grade c; //“人造”出Grade类型的变量c,用来接收函数的判断结果。 Grade GetGrade(u8 u8Score) //这里返回的类型是Grade,而“GOOD,MEDIUM,BAD”就是属于Grade { if(u8Score<BAD\_MEDIUM) //等级分数分界线的判断 { return BAD; //BAD就是常量2,代表“差”。 } else if(u8Score>=BAD\_MEDIUM&&u8Score<MEDIUM\_GOOD) //等级分数分界线的判断 { return MEDIUM; //MEDIUM就是常量1,代表“中” } else { return GOOD; //GOOD就是常量0,代表“优” } } void main() //主函数 { a=GetGrade(98); //输入98分,a来接收判断的结果 b=GetGrade(88); //输入88分,b来接收判断的结果 c=GetGrade(68); //输入68分,c来接收判断的结果 View(a); //在电脑端观察98分的判断结果a View(b); //在电脑端观察88分的判断结果b View(c); //在电脑端观察68分的判断结果c while(1) { } } /\*---C语言学习区域的结束。-----------------------------------------------\*/ 在电脑串口助手软件上观察到的程序执行现象如下: 开始... 第1个数 十进制:0 十六进制:0 二进制:0 第2个数 十进制:1 十六进制:1 二进制:1 第3个数 十进制:2 十六进制:2 二进制:10 分析: 98分的判断结果a为0,0代表“优”。 88分的判断结果b为1,1代表“中”。 68分的判断结果c为2,2代表“差”。 【78.4 如何在单片机上练习本章节C语言程序?】 直接复制前面章节中第十一节的模板程序,练习代码时只需要更改“C语言学习区域”的代码就可以了,其它部分的代码不要动。编译后,把程序下载进带串口的51学习板,通过电脑端的串口助手软件就可以观察到不同的变量数值,详细方法请看第十一节内容。