RTT设置删除空闲钩子函数想到函数指针和回调函数
Posted 何事误红尘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RTT设置删除空闲钩子函数想到函数指针和回调函数相关的知识,希望对你有一定的参考价值。
一、概述
学习RTT时,看到设置和删除空闲钩子函数接口:
rt_err_t rt_thread_idle_sethook(void (*hook)(void));
rt_err_t rt_thread_idle_delhook(void (*hook)(void));
接口传入参数void (*hook)(void)
该怎么理解呢?
乍一看void (*hook)(void)
很像一个函数:返回值+函数名+(参数)。但是细看中间部分(*hook)
,又有点不对劲呀,函数名称可没有这么写的!
二、函数指针
如果没有小括号:void *hook(void)
,这个很肯定就是一个函数。增加小括号以后,优先级改变,(*hook)
使得*
和hook
组合,成为一个指针。
所以void (*hook)(void)
表示:hook是一个指针,指向一个函数。这个函数参数为void,返回值也是void。
2.1 函数指针的使用
既然明确了是一个指针,那么就可以当成一个普通指针来使用。以前使用一个整形指针如下:
int *p = NULL;
int i = 10;
p = &i;
现在函数指针也是如此:
void (*pf)(void) = NULL;
pf = &fun;
(*pf) ();
看下运行结果:
2.2 * (int * )&p
在上面赋值函数指针时,使用了pf = &fun;
,还可以使用另一种方式:
void (*pf)(void) = NULL;
...
//pf = &fun;
*(int*)&pf=(int)fun;
(*pf) ();
先看下运行结果:
那么*(int*)&pf=(int)fun;
该怎么理解呢?先看等式的左值,可以分为三层:
&pf
,显然这是取地址。pf
是我们定义的函数指针,&pf
也就是求指针变量 pf 本身的地址。(int*)
,这是进行强制转换。(int*)&pf
表示将地址强制转换成指向 int 类型数据的指针。- 最外层的* ,也就是按照地址进行取值。在2.1节
printf("p point value = %d\\r\\n", *p);
,就是这样的形式啊。
再看等式的右值。fun是函数名,也就是函数地址。(int)fun 表示将函数的入口地址强制转换成 int 类型的数据。
所以*(int*)&pf = (int)fun;
表示将函数的入口地址赋值给指针变量 pf。
那么为什么要使用函数指针呢?
你不会每天都是用函数指针。但是,它们确有用武之地,最常见的两个用途是转换表(jump table)和作为参数传递给另一个函数。《C和指针》
三、回调函数
可以看出,在RTT设置删除空闲钩子函数中,正是第二种情况:作为参数传递给另一个函数。
使用这种技巧的函数被称为回调函数(callback
function),因为用户把一个函数指针作为参数传递给其他函数,后者将“回调”用户的函数。《C和指针》
回调函数有什么好处呢?我的理解是,便于分层,使得程序架构更清晰,降低耦合。
尤其是在多人共同完成时,有人做驱动,有人做逻辑应用。做驱动无需关系中断内需要做什么,预留出接口即可。做应用也不必关心中断内如何调用,只需要实现回调函数,注册一下就行了。这样既能同步进行开发,也使得程序更加清晰。
追踪了下RTT的设置空闲函数:
void rt_thread_idle_sethook(void (*hook)(void))
{
rt_thread_idle_hook = hook;
}
static void rt_thread_idle_entry(void *parameter)
{
while (1)
{
#ifdef RT_USING_IDLE_HOOK
if (rt_thread_idle_hook != RT_NULL)
{
rt_thread_idle_hook();
}
#endif
rt_thread_idle_excute();
}
}
RTT启动函数rtthread_startup
中初始化了空闲线程,而线程函数中通过函数指针,最终调用了void (*hook)(void)
指向的用户函数(如果开启了宏定义)。
这也就是前面说的,我们不必关心空闲线程具体怎么初始化,线程函数具体如何实现。只需要把我们想在空闲线程内做的事情封装成函数,通过函数指针传进去就行了。
以上是关于RTT设置删除空闲钩子函数想到函数指针和回调函数的主要内容,如果未能解决你的问题,请参考以下文章