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;该怎么理解呢?先看等式的左值,可以分为三层:

  1. &pf,显然这是取地址。pf是我们定义的函数指针,&pf 也就是求指针变量 pf 本身的地址。
  2. (int*),这是进行强制转换。(int*)&pf 表示将地址强制转换成指向 int 类型数据的指针。
  3. 最外层的* ,也就是按照地址进行取值。在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设置删除空闲钩子函数想到函数指针和回调函数的主要内容,如果未能解决你的问题,请参考以下文章

回调函数和钩子函数

回调函数和钩子函数的说明

钩子函数和回调函数的区别

将成员函数指针设置为空闲函数指针

钩子函数 和回调函数

Callback函数详解(我感觉,回掉函数的本质是函数指针,在业务做循环处理的时候,调用一下通知外部)