1.概念
首先先了解一下回调函数的概念:
回调函数就是一个被作为参数传递的函数。在C语言中,回调函数只能使用函数指针实现,在C++、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数。
针对C语言特定来说:
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
通俗的讲:回调函数A本身由实现者定义,定义完成之后把函数A的指针(地址)作为形参在传递给另一个函数B,函数B在调用过程中会通过形参调用函数A,完成相应功能。
2.机制(流程)
⑴定义一个回调函数;
⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;
⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
3.意义
因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。
通俗来讲就是在实现函数的过程中,调用者通过形参就可以判断出会有相应的函数来处理不同的相似事件。
4.函数指针
说一句大白话:函数指针是指向函数的指针。函数指针也是一种指针,它指向的不是整型,字符型而是函数。在C中,每个函数在编译后都是存储在内存中,并且每个函数都有一个入口地址,根据这个地址,我们便可以访问并使用这个函数。函数指针就是通过指向这个函数的入口,从而调用这个函数。
函数指针的定义:
//example 1
void (*test1)(int a, int b) = NULL;
//example 2
void (*test2)(int a, int b);
5.代码案例
先来个简单的:
//simple example
#include "stdio.h"
void test()
{
printf("This is a test func.\n");
return;
}
void use_callback(void (*pfuc)())
{
(*pfunc)();
return;
}
int main()
{
use_callback(test);
return 0;
}
来个常见的加减乘除的例子:
#include <stdio.h>
float Add(float x, float y)
{
return x + y;
}
float Sub(flaot x, flaot y)
{
return x - y;
}
flaot Mul(flaot x, float y)
{
return x * y;
}
float Div(float x, float y)
{
return x / y;
}
//2 types to use callback functions
//by struct
typedef struct
{
float (*fst_add)(float x, float y) = NULL;
float (*fst_sub)(float x, float y) = NULL;
float (*fst_mul)(float x, float y) = NULL;
float (*fst_div)(float x, float y) = NULL;
}EXAMPLE1;
//by function
float example2(float x, float y, float (*func)(float, float))
{
return (*func)(x, y);
}
int main()
{
EXAMLPLE1 * data;
data -> fst_add = Add;
data -> fst_sub = Sub;
data -> fst_mul = Mul;
data -> fst_div = Div;
printf("use callback function by struct.\n")
printf("1.5 add 1.2 is %f, 1.5 sub 1.2 is %f,
1.5 mul 1.2 is %f and 1.5 div 1.2 is %f",
data -> fst_add(1.5, 1.2), data -> fst_sub(1.5, 1.2),
data -> fst_mul(1.5, 1.2), data -> fst_div(1.5, 1.2));
printf("use callback function by function.\n");
printf("1.5 add 1.2 is %f, 1.5 sub 1.2 is %f,
1.5 mul 1.2 is %f and 1.5 div 1.2 is %f",
example2(1.5, 1.2, Add), example2(1.5, 1.2, Sub),
example2(1.5, 1.2, Mul), example2(1.5, 1.2, Div));
return 0;
}
6.结语。
核心要点就是:回调函数是通过函数指针调用的函数。
我之前还讲过JAVA中的回调函数,里面有关于同步回调与异步回调的介绍,二者虽然语言不通,但是关于同步与异步的概念都是相同的,区别在于开辟新的线程Thread的函数调用不同。感兴趣的可以去我的另一篇阅读,或许会有新的收获。
7.同步与异步
之前的案例都是同步的案例,下面写一个简单的异步代码,异步回调就是在创建的新线程中调用回调函数
下面是C++中创建线程的基本样例。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int Double(int x)
{
printf("Double in.");
sleep(500);
x = x * 2;
printf("Double out.");
return x;
}
int main
{
pthread_t id;
int thread_ret;
int data;
thread_ret = pthread_create(&id, NULL, (void *)Double, data);
if (thread_ret)
{
err_exit(err, "can't create thread");
printf("Create pthread error!");
return -1;
}
printf("pthread running.");
sleep(800);
pthread_detach(id);
printf("pthread over.");
return 0;
}
//上述例子只是传递了一个参数,想要传递多个参数,可以用struct代替data,来实现多个参数的传入。
上述例子只是传递了一个参数,想要传递多个参数,可以用struct代替data,来实现多个参数的传入。
#include <stdio.h>
#include <pthread.h>
void test()
{
sleep(100);
printf("just for test.");
return;
}
void call_then_back_func(void (*func)())
{
func();
}
int main()
{
pthread_t id;
int thread_ret;
thread_ret = pthread_create(&id, NULL, (void *)call_then_back_func, test);
if(thread_ret)
{
err_exit(thread_ret, "can't create thread");
printf("Create pthread error!");
return -1;
}
printf("pthread is running.");
sleep(500);
pthread_detach(id);
printf("pthread is over.");
return 0;
}