陆志平 胡晨骏
摘要:在根据不同条件选择执行不同函数的程序中,if-else if-elses或者witch/case结构需要经过多次匹配且执行效率较低。该文对函数指针进行深入分析与研究,提出了采用函数指针数组解决此类问题的观点,提高了程序的简洁性与效率。
关键词:函数指针;数组;switch/case
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2015)13-0230-02
Abstract: In the program that perform different functions according to different conditions, the structure of if-else if-else or switch/case need to go through many times and low operating efficiency. This paper makes a deep analysis and research on the function pointer, have brought forward the viewpoint adopt the function pointer array to resolve this kind problem, that have raised program elegance and efficiency.
Key words: function pointer;array;switch/case
在项目开发中经常会遇到根据不同条件选择不同函数的问题。例如项目中需要调用各自的函数处理不同类别的信号,这些信号采用统一的编码表示。如:zyc000XXXXX、zyc001XXXXX等,编码的3-5位为0-9之间的数字,线性排列,分别表示不同种类的信号。后面五个字符标识该类别中的不同信号。在编程处理时,一般会想到采用if-else if-else或者switch-case结构来处理[1]。但是当判断的条件较多时,程序就会变得冗长、复杂,且效率降低。本文研究采用函数指针解决此类问题,减少冗余代码,使得代码更为简洁、高效[2-3]。
1 函数指针
C语言的函数在调用时会在内存中占用一段存储空间,这段存储空间有一个起始地址,这个起始地址称为函数的入口地址,即函数的指针[4]。在程序中,函数一般是通过函数名来调用的。与数组名类似,函数名也代表了函数的入口地址,是一个指针常量[5]。
指针既然可以指向整型、字符型、数组等类型,当然也能指向一个函数。因此可以定义一个指针变量,让其值等于函数的入口地址,此指针变量即为指向函数指针变量[6],其存放的值即为函数指针。然后可以通过这个指针变量来调用该函数[7]。
在C语言中,变量必须先定义后使用,指针变量也不例外[8]。函数指针变量的定义格式为:
类型标识符 (*指针变量名)( [ 形参类型1, 形参类型2,..., 形参类型n ] ) [9]
其中:
类型标识符为指针变量所指向的函数的返回值类型。形参类型指的是函数指针所指向函数的形参的数据类型。若是函数没有形参,定义时可省略[10]。
例如:
int (*p)(int, int);
本语句定义了一个指向函数的指针变量,此函数返回值类型为int类型,有两个int类型的参数[11]。
在初始化指针变量时,只需要把函数名赋值给指针变量即可[12]。使用指针变量调用函数可以采用如下格式:
(*指针变量名)(实参列表) [13]
例如下列代码完成了一个函数指针变量的定义、初始化以及调用函数的过程:
int max(int x, int y){
/*函数体*/
}
int main(void){
int a=3,b=4;
int max(int,int); /*max函数的声明*/
int (*f) (int x, int y); /*定义一个函数指针变量f */
f=max; /* 将max函数的入口地址赋给指针f */
f(a,b); /*通过函数指针变量f调用max函数 */
}
上述代码中,在给函数指针变量f赋值时,是将max函数的入口地址赋给f,而函数名max代表的就是函数的入口地址,所以赋值时max不需要括号和参数,仅需要函数名即可。赋值后,函数指针f就指向函数max的入口地址,通过f(a,b)即完成了函数max的调用。
2 函数指针数组应用研究
单个函数指针的应用与函数名类似,但函数指针数组在处理具有大量条件与函数关联时具有很大的优势[14]。
如前言中所述,信号为zyc000XXXXX、zyc001XXXXX等字符串数据,程序接收到传过来的信号后,取其第3-5位的字符,并将其转换为十进制整数,其值为0-999,这里将它称为类型码,要求每一个类型码对应一个函数来进行处理。
首先讨论采用switch()来对类型码进行判断[15],匹配成功后调用相应的函数,实现方法如下:
witch(i){ /* 假设i为类型码 */
case 0: fun0(); break;
case 1: fun1 (); break;
…
case 999: fun999 (); break;
default: break;
}
从上述代码可以看到,这样判断的次数最少为1次,最多为1000次,平均为500次。而且每次接收到信号后都要进行判断,系统效率极低。
如何提高程序的效率?我们可以将每一个信号的类型码(0-999)类型绑定一个函数。程序接收到信号后,根据其类型码值0-999便可以直接调用绑定的函数。而绑定函数的功能则可以通过函数指针数组来完成。
在程序中定义一个1000个元素的函数指针数组,并将其元素初始化为定义好的函数的指针。这样,类型码的值对应着函数指针数组的下标,从而完成了类型码与函数指针的绑定。
实现方法如下:
/* 假设信号字符串为str,其类型码为整型数值idata */
#include
int fun0(string str){ …}
int fun1(string str){ …}
…
int fun999(string str){ …}
int main(void){
/* 定义函数指针数组并初始化 */
int (*p[1000])(string)={fun1, fun2,…,fun999};
/* 这里的idata为信号的类型码 */
int type=idata;
/*通过 (*p[ idata ])( str ) 实现绑定函数的调用*/
(*p[ idata ])( str ) ;
return 0;
}
从上面的方法可以看到,采用函数指针数组后,只需要一次调用就可以实现按需调用函数的功能,可见无论是程序编写的简洁性或者程序运行的效率都远远高于采用switch-case结构[16]。
3 结束语
函数指针是C/C++中一个非常重要的知识,但由于其概念较为抽象,使用技巧性强,应用复杂,且如果使用不当,会导致很严重的错误[17],所以很多人没有认识到它在程序编写中的作用。通过本篇介绍,希望大家合理的利用函数指针,设计出更为简洁、高效的程序。
参考文献:
[1] 谭浩强. C程序设计[M]. 北京: 清华大学出版社, 2011: 220-222.
[2] Chow F, Chan S, Kenny R, et al. A new algorithm for partial redundancy elimination based on SSA form[C]// Proc of ACMSIGPLAN Conference on Programming Language Design and Implementation. New York: ACM Press, 1997: 273-286.
[3] Kennedy R, Ruthing O, LIU Shin-ming, et al. Partial redundancy elimination in SSA form[J]. ACM Trans on Programming Language and Systems, 1999, 21(3): 627-630.
[4] 苏小红, 王宇颖, 孙志岗. C语言程序设计[M]. 北京: 高等教育出版社, 2011: 264-272.
[5] Reek K A. C和指针[M]. 北京: 人民邮电出版社, 2008: 33-34.
[6] Peter Van, Der LinDer. C专家编程[M]. 北京: 人民邮电出版社, 2008: 230-232.
[7] stephen Prata.C Primer Plus[M]. 北京: 人民邮电出版社, 2005: 236-238.
[8] Kernighan B W, Ritchie D M. C程序设计语言[M]. 北京: 机械工业出版社, 2004: 79-80.
[9] Harbison III SP, Steele Jr GL[M]. C语言参考手册. 北京: 机械工业出版社, 2003: 95-97.
[10] 许永达. C语言指针错误的分析及调试[J]. 计算机系统应用,2013,23(3): 153-155.
[11] 古辉, 乔凯旋. C++指针机制与源文件关联关系的可视化研究[J]. 计算机系统应用,2012,21(7): 238-238.
[12] 刘宏, 李飒. C语言中用指针指向函数的方法及其高级处理技巧的研究与应用[J].东北农业大学学报.1994,25(2):186-189.
[13] 何灵敏, 许翔, 陆慧娟, 等. C++教学中变成习惯的养成[J]. 计算机教育, 2011(9): 64-67
[14] 郭曦, 何炎祥, 张焕国, 等. 一种改进的指针安全分析算法[J]. 武汉大学学报: 理工版, 2010, 56(2): 170-174.
[15] 龚松显, 董锐, 刘跃宣. 用函数指针替代Switch/Case语句的程序设计方法[J]. 单片机与嵌入式系统应用, 2014(9): 14-15.
[16] 姚宇峰. 面向软件可信性的可信指针分析技术综述[J]. 计算机应用研究, 2012, 29(2): 427-430.