虽然网上有许多讲回调函数的例子,下面还是聊聊自己对回调函数的理解吧,若有理解偏差的地方,还希望看过的朋友能提提宝贵意见,定当感谢不已。
1回调函数定义:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,
当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,
而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
2 要说明的是:
回调函数的定义和一般函数没有什么区别。一般的函数调用(同步调用)就直接用函数名,
同时传递相应的参数就实现函数的调用了。
而回调函数的调用要使用指向回调函数的指针的来实现。
3 回调函数的具体实现:
回调函数(A)的调用是把回调函数的地址作为另一个函数(B)的参数,通过B中一个指向回调函数A的地址的指针来实现回调函数A的调用。在回调函数被调用的过程中,没有使 用回调函数的函数名,实际使用的是回调函数的地址。
4 可以这样理解:
回调函数的机制,有点给别人做嫁衣的感觉,回调函数本身实现了一定的功能,但是最后被调用的时候(发挥它的作用的时候)不是用的自己的名字,而是把自己的地址给别人,用别人的名字来实现本回调函数实现的功能。所以说回调函数式伟大的,她默默的在奉献,光鲜却给了别人。
5 一个函数要说她是回调函数,那么她的地址要作为另一个函数的参数。否则就是一般的函数。一般的函数调用时用的是函数本身的名字。
实例代码如下:
#include<stdio.h>
typedef int (*pq_callback)(int x,int y);
typedef struct node
{
int name;
pq_callback callback;
struct node * next;
}node_t;
//回调函数
int pq_add(int x,int y)
{
return x+y;
}
//回调函数
int pq_sub(int x,int y)
{
return x-y;
}
//回调注册函数
int pq_register_callback(pq_callback fn,node_t* node)
{
node->callback = fn;
return 0;
}
int main(int argc,char **argv)
{
node_t node;
int x = 4;
int y = 5;
/*注册回调函数*/
pq_register_callback(pq_sub,&node);
/**
*注册的回调函数被调用,
*但是没有用回调函数本来的函数名,
*回调函数默默的奉献了自己,成就了别人。
**/
int ret = node.callback(x,y);
printf("ret = %d\n",ret);
return 0;
}
上面的例子展示了回调函数的运用
6应用回调函数的场合:
6.1什么时候该用回调函数呢,使用回调函数有什么好处呢?
6.2上面的例子展示了回调函数的基本用法,回调函数的应用是非常广泛的。通常,当我们想通过一个统一接口实现不同内容的时候,用回调函数来实现就非常合适。任何时候,如果你所编写的函数必须能够在不同的时刻执行不同的类型的工作或者执行只能由函数调用者定义的工作,你都可以用回调函数来实现。许多窗口系统就是使用回调函数连接多个动作,如拖拽鼠标和点击按钮来指定调用用户程序中的某个特定函数。
6.3 回调函数还可以实现代码的复用,在不同情况下用统一的接口调用不同的回调函数,统一接口这部分即实现了代码的复用。
7 下面的例子就用回调函数实现的函数的统一接口:
如果有一条链表,链表的value域是int类型,那么要查找链表中有没有给定的值的话,可以用下面的代码实现:
/*******************************************************
* Author: pengqian
* Created: Oct 18 2013
* Copyright: (C) Copyright 2013 pengqian
* email: pengqian652@qq.com
* funtion: test callback
********************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_SIZE 100
typedef struct node{
int value1;
char value2[MAX_SIZE];
void *value_add[2];
struct node* next;
}Node;
Node *node_head;
/********************************************
*name: create_list
*funtion:创建链表
*input: char *buf,long len
*output: Node *
*return: Node *
**********************************************/
Node * create_list(int value1,char *value2,int value2_len)
{
Node *node;
node =malloc(sizeof(Node));
if (!node)
return NULL;
node->value1 = value1;
memcpy(node->value2,value2,value2_len);
node->value_add[0] = &node->value1;
node->value_add[1] = node->value2;
node->next = node_head;
node_head = node;
return node;
}
/********************************************
*name: search_int_value
*funtion:查询链表中的vlaue
*input: Node *head,const char *value
*output: Node *
*return: Node *
**********************************************/
Node *search_value(Node *head,const int value)
{
Node *cur = head;
while(cur!=NULL)
{
if(cur->value1==value)
{
break;
}
else
{
cur = cur->next;
}
}
return cur;
}
int main(int argc,char **argv)
{
int i =0;
Node *node;
Node *head;
char buf[MAX_SIZE] = "abcdefghij";
char *p = buf;
/*创建一条5个节点的链表*/
for(i = 0;i<5;i++)
{
head = create_list(i,p,2);//5个结点的值分别为0 "ab",1 "cd",2 "ef", 3"gh", 4"ij"
p =p+2;
}
int a =3;
node = search_value(head,2);
printf("node->value1 = %d\n",node->value1);//打印结果为2
return 0;
}
上面的 search_int_value(Node *head,const int value)函数实现了在链表中查找给定数值的功能,
但是这个函数有一定的局限性,她只能查找int类型的数值,不能查找char类型的数值。
8 其实我们更希望令查找函数与类型无关,这样它就能用于查找存放任何类型值的链表了,
因此必须改变比较的方式,而借助回调函数就可以达到这个目的。
我们编写一个函数(回调函数),用于比较两个同类型的值,然后把一个指向这个函数的指针作为参数传递给查找函数,查找函数调用这个比较函数来执行比较,采用这个方法,任何类型的值得都可以进行比较。
我们还必须给查找函数传递一个指向待比较的值的指针而不是值本身,也就是一个void *类型的形参,(此处就是指针的妙处所在,在不知道数据类型的情况下,可以用void *指针)。
这个指针会传递给回调函数,进行最终的比较。这样的修改可以让我们传递指向任何类型的指针到查找函数,从而完成对任何类型的比较,这就是指针的好处,我们无法将字符串、数组或者结构体作为参数传递给函数,但是指向它们的指针却可以。
9在这里,能不能只用一个search_list()函数来实现既可以查找int类型,也可以查找char类型呢?.当然可以,那就要用到回调函数。注意下面compare()函数的实现技巧。
10 下面的代码就实现了这样的功能:
/*******************************************************
* Author: pengqian
* Created: Oct 18 2013
* Copyright: (C) Copyright 2013 pengqian
* email: pengqian652@qq.com
* funtion: test callback
********************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_SIZE 100
#define INT_DATA 1
#define CHAR_DATA 2
typedef struct node{
int value1;
char value2[MAX_SIZE];
void* value_add[2];
struct node* next;
}Node;
Node *node_head;
/********************************************
*name: create_list
*funtion:创建链表
*input: int value1,char *value2,int value2_len
*output: Node *
*return: Node *
**********************************************/
Node * create_list(int value1,char *value2,int value2_len)
{
Node *node;
node =malloc(sizeof(Node));
if (!node)
return NULL;
node->value1 = value1;
memcpy(node->value2,value2,value2_len);
node->value_add[0] = &node->value1;
node->value_add[1] = node->value2;
node->next = node_head;
node_head = node;
return node;
}
/*定义回调函数指针*/
typedef int (*fun_callback)(void const *a,void const *b,int data_type);
//回调函数
int compare(void const *a, void const *b,int data_type)
{
switch(data_type)
{
case INT_DATA:
{
if(*((int *)a)==(*(int *)b))
{
return 0;
}
else
return -1;
}
break;
case CHAR_DATA:
{
if(!strcmp((char *)a,(char *)b))
{
return 0;
}
else
return -1;
}
break;
default:
break;
}
}
//用回调函数实现了统一接口
Node *search_list(Node *head,fun_callback fn,void const *value,int len,int data_type)
{
Node *cur = head;
while(cur!=NULL)
{
if(len==sizeof(int))
{
if(!fn(cur->value_add[0],value,data_type))
{
break;
}
else
{
cur = cur->next;
}
}
else
{
if(!fn(cur->value_add[1],value,data_type))
{
break;
}
else
{
cur = cur->next;
}
}
}
return cur;
}
int main(int argc,char **argv)
{
int i =0;
Node *node;
Node *head;
char buf[MAX_SIZE] = "abcdefghij";
char *p = buf;
/*创建一条5个节点的链表*/
for(i = 0;i<5;i++)
{
head = create_list(i,p,2);//5个结点的值分别为0 "ab",1 "cd",2 "ef", 3"gh", 4"ij"
p =p+2;
}
int a =3;
node = search_list(head,compare,&a,4,1);
printf("node->value1 = %d\n",node->value1);//打印结果为3
node = search_list(head,compare,"ab",2,2);
printf("node->value2 = %s\n",node->value2);//打印结果为ab
return 0;
}
11 以上就是对回调函数的全部论述,代码能在gcc下面编译通过,可运行查看结果。
本文在阅读大量资料的情况下总结了自己的观点,内容原创,版权归博主所有,欢迎留言,转载请注明出处。