最近在阅读cJSON的源代码,在看见如下代码是产生了,深深地疑惑,这个是什么声明?用来干嘛的?
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
在读懂这两句代码之前我们先来了解熟悉两个概念——函数指针和指针函数,想必和我一样处于C语言入门阶段的小伙伴对这两个概念并不是十分熟悉,接下来我们一起学习一下。
函数指针
函数指针首先它是一个指针变量,其次它是指向函数的,正如每个变量都有地址,我们知道每一个函数也是都有一个入口地址的,函数指针指向的就是函数的入口地址。
我们来看一下函数指针的声明:
/*声明一个函数指针*/
//正确的写法 这是一个函数指针
int (*a)(void *);//a是一个函数指针,它所指向的函数有一个void*类型的参数,返回类型是int
//错误的写法 这是一个指针函数
int *b(void *);//b是一个函数,这个函数带有一个void*类型的参数,返回类型是int
函数指针是一个指针,它需要指向一个函数的地址,对它的赋值方法有两种:
//test是函数指针
int (*test)(int x, int y)
//function是一个函数
test = &Function;
test = function;
这两种赋值方法都是等价的,与数组一样,函数名代表了一个函数的入口地址。
对于函数指针的调用也有两种方法:
test = (*test)();
test = test();
这两种方法也是相同的,当然为了使得代码更清楚可以使用带*运算符的,表明这是对指针的解引用。
下面我们通过一个简单的代码来看看如何使用函数指针:
#include <stdio.h>
int function();
int main(void)
{
//函数指针赋值
//两种写法都可以看个人喜好
//int (*test)(void) = function;
int (*test)() = &function;
//函数指针调用
//同样的两种方式
//test();
(*test)();
return 0;
}
int function()
{
printf("Here!\n");
}
//输出结果:
Here!
指针函数
指针函数与函数指针相比会更好理解,同时它也更常见一些,它的本质就是一个函数,其返回值的类型为指针。下面我们看一下代码:
#include <stdio.h>
int *test();
int main(void)
{
int *y;
y = test();
return 0;
}
int *test()
{
printf("Here!\n");
}
//输出结果:
Here!
实际案例
下面开始分析有关代码,首先是cJSON_Hooks结构体:
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
这一部分一开始也是困扰了很久,对于刚开始入门C语言的小伙伴来说,这两句声明到底是什么意思,为什么要这样做,想必会是一头雾水。首先根据上文介绍的我们可以清楚知道:
- malloc_fn是一个函数指针,它所指向的函数具有一个size_t类型的参数,返回void类型的指针。
- free_fn是一个函数指针,它所指向的函数具有一个void*类型的指针,无返回值。
那么为什么是这样声明呢,我们可以来看一下头文件<stdlib.h>中的malloc和free的函数原型:
void* malloc(size_t size);
void free(void* p);
- 这里我们看到malloc的参数是size_t类型,返回的是一个void*类型的指针。
- free的参数是void*的指针,无返回值,void*类型的指针是为了能够释放各种类型的参数的内存。
于是通过对比我们就可以知道,cJSON_Hooks结构体实际上做的事情就是声明用户自定义的malloc和free函数指针。
cJSON.c中:
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
- 这里声明了两个静态函数指针(cJSON_malloc和cJSON_free),并且分别将它们各自指向malloc函数和free函数。
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = malloc;
cJSON_free = free;
return;
}
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
}
- 如果hooks未声明,则对两个函数指针进行重置。
- 如果hooks以声明,则判断hooks的malloc_fn和free_fn是否存在,如果存在则让分别cJSON_malloc和cJSON_free指向它,如果不存在,则使用默认的malloc和free函数。
- 以上代码主要作用其实是提供一个接口让用户定义自己的内存管理函数,如果没有定义,则使用默认的函数。