函数指针
1.函数指针的定义:
void (*p)(void) :没有返回值,没有参数的函数指针p
void (*p)(int,int) :没有返回值,参数为两个整型的函数指针p
int (*p)(void) :返回值为整型,没有参数的函数指针p
char (*p)(int,int) :返回值为字符型,参数为整型的函数指针p
..................................
2.函数指针的赋值:
void fun1()
{
printf("i am is fun1\r\n");
}
int main(int argc,char*argv[])
{
void (*p1)(void);
p1 =fun1;
}
3.函数指针的执行:
int main(int argc,char*argv[])
{
void (*p1)(void);
p1 =fun1;
p1(); //简写方式
//(*p1)(); //原始方式
while(1);
}
那么问题了,我们有函数不去调用,为什么还要定义一个函数指针去执行对应的函数,再去用函数指针来执行,看上去多此一举,是吧?是的,这里就是多此一举,不过有一个好处就是定义的函数指针可以随意指向与其类型一致的任意函数,这里只是指向fun1,同样也可以指向fun2。
回调函数
下面我们用两个.c文件和一个run.h文件来实现另一个功能,定义main.c和run.c文件,在run.c和run.h的内容如下:
#include<Windows.h>
//定义函数指针
void (*p)(void);
//运行函数指针
void run()
{
while(1)
{
(*p)();
Sleep(1000);
}
}
#ifndef RUN_H_
#define RUN_H_
void run(void);
#endif
run.c中定义了一个函数指针,且在run函数中直接对函数指针p运行,此方式存在着一定的bug,使用者在main.c中调用了run函数,却没对函数指针赋值,那不是会出现段错误了吗?我们先来尝试一下,main函数代码如下:
#include<stdio.h>
#include "run.h"
//声明函数指针p,不然不能调用
extern void (*p)(void);
void fun1()
{
printf("i am is fun1\r\n");
}
void fun2()
{
printf("i am is fun2\r\n");
}
int main(int argc,char*argv[])
{
run();
}
果不其然,出现了段错误。
为了避免悲剧的诞生,需要对run.c中的run函数进行优化,定义函数指针p的时候对其初始化 void (*p)(void) = NULL 操作,在执行函数指针p之前判断p是否赋值这样就不会出现错误了,if(p!= NULL) (*p)();
main.c中添加对函数指针的赋值,运行程序,run.c中的run函数会每秒调用一次main.c中的fun1函数。
一般在run.c中添加一个安装函数 install_fun,该函数带有一个函数指针参数,直接将函数名传进来,其中的 p是我们之前在run.c中定义的函数指针,形式是 void (*p)(void),具体如下:
//添加安装函数
void install_fun(void (*pp)(void))
{
p = pp;
}
这样在main.c可以删除对函数指针p的声明,直接声明install_fun函数,具体代码如下:
#include<stdio.h>
#include "run.h"
void install_fun(void (*p)(void));
void fun1()
{
printf("i am is fun1\r\n");
}
int main(int argc,char*argv[])
{
install_fun(fun1) ;
run();
}
运行结果跟上面一样,但这种看上去更加牛X,瞬间提高了逼格,以后我们应该学着去写一些有逼格的东西,显得自己不是一个菜鸟哈........
你以为结束了吗?远远没有,有时候我们想从底层拿些数据,是不是可以通过回调函数来拿取呢?肯定可以的,修改上面的代吗可以做到,首先修改run.c文件中的函数指针增加参数int 形式如: void (*p)(int) 在run函数中,添加一个计数变量,循环自加,并将此变量传给应用层的回调函数中。
#include<Windows.h>
//定义函数指针
void (*p)(int) = NULL;
//运行函数指针
void run()
{
int count = 0;
while(1)
{
if(p!= NULL)
(*p)(count);
count++;
Sleep(1000);
}
}
//添加安装函数
void install_fun(void (*pp)(int))
{
p = pp;
}
在main.c中为fun1添加一个参数 int i 来接收底层传入的参数count,这样就可以通过回调函数的形式来接收底层传入的参数了。
#include<stdio.h>
#include "run.h"
void install_fun(void (*p)(int));
void fun1(int i)
{
printf("i am is fun1 time is %d s\r\n",i);
}
int main(int argc,char*argv[])
{
install_fun(fun1) ;
run();
}
运行结果如下,成功打印出run.c文件run函数中cout变量传上来的值。
到这里,我们可以把单片机采集的传感器数据都可以使用回调函数的新式来传入到main.c中,前提是你得把每一个的底层封装好,甚至做到客户不可见,我只管给你数据,你只管来调用就行。
这里同样有一个疑问,既然底层可以传回数据到应用层,那么应用层可以传数据到底层吗?当然可以的,这里修改函数指针形式为 int (*p) (int) main.c和run.c的代吗如下,可以看到应用层传给底层一个2020的数据。
run.c 文件代码
#include<Windows.h>
#include <stdio.h>
//定义函数指针
int (*p)(int) = NULL;
//运行函数指针
void run()
{
int count = 0;
while(1)
{
if(p!= NULL)
{
int r = (*p)(count);
printf("%d \r\n",r);
}
count++;
Sleep(1000);
}
}
//添加安装函数
void install_fun(int (*pp)(int))
{
p = pp;
}
Main.c 文件代码
#include<stdio.h>
#include "run.h"
void install_fun(int (*p)(int));
int fun1(int i)
{
printf("i am is fun1 time is %d s\r\n",i);
return 2020;
}
int main(int argc,char*argv[])
{
install_fun(fun1) ;
run();
}