用函数指针替代Switch/Case语句的程序设计方法

来源:本站
导读:目前正在解读《用函数指针替代Switch/Case语句的程序设计方法》的相关信息,《用函数指针替代Switch/Case语句的程序设计方法》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《用函数指针替代Switch/Case语句的程序设计方法》的详细说明。
简介:单片机程序中,当Switch/Case语句分支较多、处理代码较长、处理情况较为复杂时,逻辑修改和程序调试均存在一定的困难。针对该问题,本文给出了使用函数指针替代Switch/Case语句的实现思路以及相对应的代码模型,为其他类似的代码实现提供参考。

引言

在单片机程序中,诸如键盘按键扫描、菜单处理等多种逻辑功能,在代码上常采用Switch/Case语句的实现方式。Switch/Case语句是一种简单、初级的逻辑表达式,当代码较为复杂时,不利于程序的功能调试和逻辑修改[1],程序的可扩充性和可移植性都受到影响。为了在单片机常用的结构化程序设计中避免Switch/Case语句过于冗长,提出一种使用函数指针来替代Switch/Case语句的实现思路,并给出两种情况下的代码模型。事实证明,该方法可使程序的结构清晰、易于维护,可提高单片机程序的可读性和设计效率。

1Switch/Case语句的代码模型及特点

1.1 Switch/Case语句代码模型

Switch/Case是C语言中的基本语句,其使用方法在大量教材及书籍中均有介绍[2],这里不再赘述。一般来说,Switch/Case语句代码模型如下:

//功能代码实现

void function(void){

//程序处理

switch (PrmValue){

case Prm_A:

//程序处理

break;

case Prm_B:

//程序处理

break;

case Prm_C:

//程序处理

break;

……

}

}

在该代码模型中,假定function函数形参及返回值均为void类型,其使用Switch/Case分支语句进行不同情况下的程序处理。PrmValue是从前面的程序处理代码中获得的表达式,Prm_A、Prm_B和Prm_C等常量是表达式的值。当表达式的值与某一个Case后面的常量表达式的值匹配时,就执行此Case后面的语句。

1.2 Switch/Case语句的不足

从模型上可以看出,对于简单的功能实现,Switch/Case语句清晰、简便;但当项目功能较为复杂,例如键盘数或菜单级数较多时[3],Switch/Case语句的判断分支较多,导致代码冗长,常常一个Case分支语句动辄跨越数十行,程序整体的可读性和可移植性降低,程序的结构不够清晰。另外,当Switch/Case语句需要扩展功能时,需要在已经臃肿的Case分支上继续“添砖加瓦”,造成了程序语句的进一步冗长,不便于后期程序逻辑功能的修改。

2 使用函数指针替代Switch/Case语句的

两种设计方法

2.1 Case表达式的值连续情况下的设计方法

在Switch/Case语句代码模型中,较为常见的一种情况是:Prm_A、Prm_B、Prm_C等常量是连续的数值。对于这种情况,设计思路是定义相关的函数指针数组[4],然后实现相对应的函数。在使用时,只需调用对应的函数指针数组元素即可。该方式下代码模型如下:

//pFun_A等相关函数的实现

void pFun_A(void){...}

void pFun_B(void){...}

void pFun_C(void){...}

……

//相关的函数指针数组的定义

void (*pFun)(void)[]={pFun_A,pFun_B,pFun_C,}

//功能代码实现

void function(void){

//程序处理

(pFun[PrmValue])();

//调用函数指针替代原本的Switch/Case语句

}

在该代码模型中,假定函数指针指向的函数形参及返回值均为void类型,PrmValue是从前面的程序处理代码中获得的表达式。设计方法中,将每个Case分支的处理代码封装成函数,并将每个函数地址按照Case表达式的值的顺序赋给函数指针数组各元素。在功能代码中,程序的实现主体只需使用PrmValue的值调用对应的处理函数即可,原本冗长的Switch/Case语句被一条简单的函数指针调用代替,形式较为简洁。使用这种设计方法,当程序需要扩展新的功能逻辑的时候,只需要依次增加函数指针数组元素的值并实现对应的函数,功能代码的主体部分不需改动。需要注意的一点是,第2种的代码模型中,假定PrmValue的值是从0开始的,对于Case表达式的值不是从0开始但Case表达式的值连续的情况,上面的代码模型仍然可以使用。例如,如果Case表达式的值是从delta开始的,在这种情况下只需要将第2种代码模型中的(pFun[PrmValue])()表达式改为(pFun[PrmValuedelta])()即可,代码的其他部分均可以保持不变。

2.2 Case表达式的值离散情况下的设计方法

第1种代码模型中,在Prm_A、Prm_B、Prm_C等数值相差较大且不连续的情况下,如果仍然套用2.1节的设计方法,函数指针数组中需要人为填充大量冗余数据,造成资源的浪费,并且在修改时需要做到精确的一一对应,程序的设计反而变得更为麻烦,失去了设计方法的本意。此时需要对第2种代码模型进行增强设计。其设计思路是通过构建一个数据结构,将离散的Case表达式的值和对应的处理函数一一对应,在功能代码中对函数指针进行轮询操作。其实现模型如下:

//pFun_A等相关函数的实现

void pFun_A(void){...}

void pFun_B(void){...}

void pFun_C(void){...}

……

//相关的数据结构及其数组的定义

typedef struct { int iValue; void(*pFun)(void)} StructFun;

StructFun mystruct[]={ {Prm_A,pFun_A}, {Prm_B,Fun_B}, {Prm_C, pFn_C}... };

//功能代码实现

void function(void){

//程序处理

for (int i=0; i<sizeof(mystruct)/sizeof(StructFun); i++){

//轮询比较,找到相等的值并调用对应的函数指针

if( PrmValue== mystruct[i].iValue )

(mystruct[i].pFun)();

}

}

在该代码模型中,构建的StructFun结构体数组实现了Case表达式的值和函数指针的一一对应。当程序需要扩展新的功能逻辑时,只需要添加StructFun结构体数组的内容并实现对应函数体即可,设计方法的优点与2.1节的设计方法类似。实际上,2.1节的设计方法是特殊情况下本设计方法的退化,两种设计方法在思路上仍是保持一致的。

结语

本文介绍的两种使用函数指针替代Switch/Case语句的方法,使程序的任务处理逻辑关系变得简洁明了,易于增加程序状态,更改程序逻辑,程序的可读性、可调试性强,减少了单片机程序设计中的错误。笔者在工程项目中验证了这两种设计方法,实际可行且快捷有效,对于单片机常用的结构化程序开发具有一定的借鉴意义。

提醒:《用函数指针替代Switch/Case语句的程序设计方法》最后刷新时间 2024-03-14 01:01:34,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《用函数指针替代Switch/Case语句的程序设计方法》该内容的真实性请自行鉴别。