深入理解函数指针变量和函数指针类型
创始人
2024-05-12 04:17:06

一、目的

在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类型的函数指针。

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

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

相关内容

热门资讯

demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...