深入理解函数指针变量和函数指针类型

一、目的

在RTOS中创建任务时一般会要求实现具体任务函数,例如在RT-Thread中任务创建函数声明如下

/**
 * @brief   This function will create a thread object and allocate thread object memory.
 *          and stack.
 *
 * @param   name is the name of thread, which shall be unique.
 *
 * @param   entry is the entry function of thread.
 *
 * @param   parameter is the parameter of thread enter function.
 *
 * @param   stack_size is the size of thread stack.
 *
 * @param   priority is the priority of thread.
 *
 * @param   tick is the time slice if there are same priority thread.
 *
 * @return  If the return value is a rt_thread structure pointer, the function is successfully executed.
 *          If the return value is RT_NULL, it means this operation failed.
 */
rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick);
void (*entry)(void *parameter)

严格的讲,这边的entry是一个函数指针类型变量,很多小伙伴可能暂时无法理解这个入参的声明方式

例如我们定义的任务执行函数的伪代码如下:

static void my_task(void *args) {
    while (1) {
        //任务循环
    }
}

此处的my_task就是我们定义的任务函数,没有返回值,只有一个void *的函数入参;任务一般都是一个while循环,例如执行具体的业务逻辑。

现在我们任务执行函数也有了,那么如何创建一个新的任务执行呢?

下面的代码片段就是创建一个新的任务

rt_thread_t my_task_t = rt_thread_create("mytask", my_task, 1024, 3, 5);

现在请大家分析下面的代码片段:

typedef int (*foo)(int *);
int (*foo)(int *);
int foo(int *);
int *foo(int *);

如果你能够很清楚的辨别其中的区别,那么本篇博文介绍的知识你已经完全掌握;否则请跟我的步伐继续走下去,相信你会收获颇丰。

在看完本篇之后肯定也就能够看明白下面的函数声明

void ( *signal(int signum, void (*handler)(int)) ) (int);

二、介绍

在c语言中我们有各种类型包括整形(int/long)、字符类型(char)、指针类型、结构体类型。

其中指针类型细分下来就有int*、char*、各个结构体指针等,还有一种大家其实可能都用过但是没有深究的函数指针类型。

函数指针类型本质是一个指针,只是这个指针指向一个函数(函数名其实就是一个地址)。

typedef(类型重定义)

有时候一些类型名字比较繁琐或者复杂我们可能会使用typedef重新定义,例如

typedef unsigned char uint8_t;
typedef int int32_t;
typedef unsigned int uint32_t;

typedef struct foo {
    //struct field
} foo_t;

//下面的两行代码效果一样,也就是foo_t等效于struct foo
struct foo a;
foo_t a;

函数指针类型
typedef int (*pfunction)(int *);

上面的代码片段就是一个函数指针类型的声明,仅接受一个int *的入参,并且返回一个int类型的返回值。

注意包围pfunction的(*)

既然我们声明了一个函数指针类型,那也就可以声明一个函数指针类型的变量,这个变量可以指向一个函数。

下面声明了pfunction类型的变量myfunction

pfunction myfunction;

函数指针变量
int (*myfunction)(int *);

此处的myfunction是一个变量,只是这个变量是一个函数指针类型的,只有一个入参int *和一个int的返回值。

//函数定义
int function_one(int *a) {
    return 1;
}
//函数指针变量
int (*myfunction)(int *);
int main() {
    myfunction = function;
}

既然myfunction是变量那么在编译后myfunction的类型是Data段,但是function_one因为是函数,所以其编译后的类型就是Code段。


函数声明
int foo(int *);
int *foo(int *);

这边foo是两个函数声明,第一个函数声明只有一个入参int*和一个int类型的返回值;第二个函数只有一个入参int*和一个int*类型的返回值。


现在我们再回头看一下文章开头的函数声明

void ( *signal(int signum, void (*handler)(int)) ) (int);

我们可以重新声明这个函数

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

通过typedef我们重新定义了sighander_t这个函数指针类型,只有一个int入参,没有返回值;signal函数声明有两个入参,一个是int类型,一个是sighander_t函数指针类型;然后这个函数返回一个sighander_t类型的函数指针。

最后,函数指针类型的变量有一个大家耳熟能详的名字就是回调函数。

至此,函数指针类型和函数指针变量就讲解结束了。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值