函数指针与回调函数新感悟

2021年5月22日12:57:47

关于函数指针的理解可以参考之前写的博文。

对于一个指针而言,我们需要考察它的几点性质:

  • 1、这个指针是什么类型的?
  • 2、这个指针的大小是多少?
  • 3、这个指针是什么时候指向什么地址的?

其实,我们对于一个指针一般只关注两点,1和3.

对于1,肯定是在声明的时候就知道这个指针应该指向什么类型。
对于2,肯定是在赋值的时候知道它指向对应的类型的地址的。
对于3,指针的大小和系统有关,一般的系统,指针大小为4字节,也就是和int类型的大小一样。

明确以上1,2点之后,我们对照着int *来看就会很明白了。

int a = 0;
int * p;
p = &a;

那么接下来我们聊聊函数指针。
现在再回顾一下,我用自己的语言来描述一下什么是函数指针。
函数指针 本质是一个指针。
结合上面关于指针的2点需要关注的点,我们对照一下函数指针该怎么去解释或者说理解。

像声明int类型的指针一样,我们应该声明一个函数类型的指针。
这个时候的疑问是,系统里没有我们需要的函数类型啊。
那怎么办?
别忘了一件事:
C语言为我们提供了声明自定义类型的工具:那就是typedef关键字。
我们一般使用这个关键字做结构体的声明,在声明结构体的时候还要结合另外一个关键字struct。

typedef struct person_s { //这里后缀s是认为添加的,我们可以理解成使用person_s这个结构体时候,必须和struct一起使用,因为现在的结构体名字是struct person_s 而不是person_s
    int age;
    char sex;
    double height;
    double weight;
};

从上面可以看到typedef的一种用法就是用来声明结构体。
还有另外一种就是为类型取别名。

typedef struct person_s person_t;

通过上面这个语句,我们就成功的为struct person_s 取了一个别名,也就是一个外号:叫person_t。 这个时候我们在需要使用struct person_s 的地方可以使用person_t进行替换了,是不是方便很多?

ok。
到这里我们认识了typedef的取别名的用法。
回到正题。声明函数类型的指针,肯定需要一个函数类型了。
那么我们就用typedef来声明一个函数为了就行了。

typedef void * (*FP)(int *, int);

上面这句话就是为函数void * (*)(int *, int);取了一个别名叫FP。

那么我们就可以使用fp去声明一个指针了。

  FP *fp1;  //这样fp1就必须指向一个形如void * (*)(int *, int)的函数。
  int a[] = {1,2,3,4,5,6,7,8};
  int n = 3;
  void * sumArray(a, n);//此函数在其他地方声明和实现的,计算一个数组前n的和并返回该值的地址(这个例子不好,主要是返回内容是一个地址了)
  //上面这个函数就是FP类型的。我们可以使用fp1来替换sumArray函数进行调用
  fp1 = sumArray;
  fp1(a,n);//这样就可以和直接调用sumArray一样的效果。

好,从上面的例子,我们隐约能够觉得,函数指针是可以被赋值的,也是可以当做被赋值过来的函数进行调用的。
慢慢品味这里的逻辑。
有了这个意识之后,我们可以更大胆一点。
如果在一个结构体里声明了一个函数指针,那么会发生什么?
看例子:

typedef void (*EAT)(char *, int);//吃的方法,传入水果的名字和数量,表示吃了几个XX水果
void (*_eat)(char * name, int n){
    //吃了n个name水果
}
typedef struct person_s{
    int age;
    EAT *eat;//
}person_t;

person_t *xiaoming = (person_t)malloc(sizeof(person_t));//给xiaoming申请一块内存
//开始给xiaoming赋值
xiaoming->age =18;
xiaoming->eat = _eat;//注意这里为xiaoming的eat方法实际赋值了,赋值为_eat方法,看清这里,是直接把函数名赋值给对应的指针

//程序某处需要调用xiaoming的eat方法
char *name = "Orange";
int n = 2;
xiaoming->eat(name,n); //开始执行_eat函数。

这个函数的赋值,和在响应需要的时候调用指定函数显示不同的功能的过程,就叫做函数的回调。这个函数就是回调函数。