【C语言更新】结构体中实现函数成员以及回调函数
文/Edward
前面说,结构体内部的成员变量可以是普通变量,数组,除了这些变量之外,还可以是指针,结构体,枚举,共用体等。综上所述的结构体内部成员中,我们可以发现一个结构体内部的成员竟然不包含函数。
往往我们在写程序时,比如定义了某一个“对象”(注意这里不是指C++,C#,Java等高级语言中的对象概念)。如在C语言中定义了一个用作显示器初始化的对象,这里定义了一个内部成员变量int width,这个变量表示了当前系统中显示器的宽度,另一个变量为int height,这个变量表示了当前系统中显示器的高度。除了这两个常规的变量之外,我们在对显示器初始化时,会调用到函数“ScreenInit(intwidth, int height);”。
对于上述的应用中,如果是简单的单一显示器是完全没有任何问题的,但是当我们这个程序需要去被外界移植的时候,每个显示器除了有不同的width和height之外,其初始化函数也可能不同。对于这种应用,我们希望这个初始化函数也被包含在整个“对象”中,这样在移植的时候,我们除了定义显示器的长度,宽度之外,再重新写一个显示器的初始化函数,即可以非常方便地将这个显示器驱动移植过去。
除了上述这个应用之外,再比如,我们在写一个嵌入式芯片的框架程序时候,可以将每一个新建的任务定义成一个结构体,这个结构体里面包含了这个任务的调度时间,优先级,堆栈大小,以及具体的任务代码。
上述的两种应用中,除了我们定义结构体的普通成员变量之外,还需要在结构体里面定义一个非常重要的元素,即函数。而我们前面已经明确交代过C语言的结构体中是不能支持函数的,那么我们能否想一个办法出来让C语言的结构体可以去嵌入一个函数功能的成员进去呢?答案显然是可以的,因为C语言的结构体内部虽然无法去直接定义一个函数,但是C语言结构体内部的成员明确可以为一个指针,我们前面说了,C语言的指针可以指向一切具有地址的东西。
因此,要在C语言结构体中实现函数成员的思路就变得很明了了,即:
在C语言结构体内部定义一个指向函数的指针;
在具体“对象”初始化的时候,将结构体中的指向函数的指针指向具体实现功能的函数;
在这个函数需要调用时进行调用。
以上就是关于C语言结构体中实现函数成员的方法,如图1所示。
图1 C语言结构体中实现函数
再补充一点,上述这种原理,先将指向函数的指针指向具体的实现函数,后面再来统一调用,这种方式就是我们在C语言里面常说的回调函数。回调函数的应用有很多,比如当我们在做单片机中断的时候,就可以将单片机中断处理函数写成一个指向函数的指针,在每次单片机程序初始化的时候,将中断里面的函数指针指向具体的中断处理函数,等到中断产生的时候,单片机就可以去调用这个指向函数的指针了。而在程序运行的时候,我们也可以随时去修改这个指向函数的指针指向的对象,使程序更加灵活。
接下来,我们来写一些代码说明一下C语言结构体中实现函数成员。这里有一个实例,写一个程序,根据输入计算一个长方形的周长或者面积,假设键盘输入的数字为1,就计算这个长方形的周长,假设键盘输入的数字为0,就计算这个长方形的面积。
上述的这个程序可以有无数种做法,由于今天我们主要讲述结构体和回调函数,那么我们就使用这两个知识点来编写程序。
首先要做的就是为这个长方形定义一个可以存储它所有相关变量的结构体,我们想一下,这个结构体用来描述长方形,长方形的两个最关键的信息就是它的长度和宽度,因此这个结构体中一定要包含这两个信息。然后,我们的要求是要计算这个长方形的周长和面积,所以我们也可以将这两个变量一并定义在结构体里面,当然如果不想定义进结构体也没问题。接着我们要求是需要同时求这个长方形的面积和周长,因此我们可以为这个结构体定义一个指向函数的指针,根据不同的选项来修改这个指针指向的函数。最后,根据输入需要,修改这个结构体中指向函数的指针指向的函数,然后调用即可。因此可以写出如图2的程序。
图2 结构体内嵌函数成员的应用