理解
函数指针
指向函数的指针。比如:
理解函数指针的伪代码
void (*p)(int type, char *data); // 定义一个函数指针p
void func(int type, char *data); // 声明一个函数func
p = func; // 将指针p指向函数func
p(1,"test"); // 调用方式1
(*p)(1,"test"); // 调用方式2
回调函数和回调
比如,B把自己函数cbkFunc()的地址告诉A,A在运行过程中执行cbkFunc()。则
回调函数:指B的函数cbkFunc();
注册回调函数:指B把函数cbkFunc()的地址告诉A;
回调:指A在运行过程中执行cbkFunc()。
code
- 无头文件.h
- 为了方便模块A和B写在了一个.c文件中
- 打印log的函数见参考博客[3],可以直接替换为printf()
FunctionPointTest.c
/*
* 理解函数指针和回调函数
*
* 假设需求:A要进行某项运动,有开始、正在做、结束3个状态,
* B需要关注这3个状态
*
* 实现方案:A提供一个回调函数注册接口,在程序开始运行时,
* B向A注册回调函数,A以回调函数的形式通知B
*
* 为了简便A和B写在一个文件里
*/
#include "D:\MyFiles\MyLog\WindowsC\mylog.h"
#include <stdio.h>
#include <windows.h>
// A和B的共同定义,一般是A的一个头文件,B会包含这个头文件:
typedef enum ENUM_EVENT {
E_EVENT_START,
E_EVENT_DOING,
E_EVENT_FINISH,
} EnumEvent;
typedef void (*EVENT_CBK)(EnumEvent type, char *data);
int regEventCbk(EVENT_CBK cbk);
// A的实现
#define TAGA "[MODULE_A]"
static EVENT_CBK gSendEvent = NULL;
int regEventCbk(EVENT_CBK cbk) {
if (cbk == NULL) {
return -1;
}
gSendEvent = cbk;
LOGI("%s{有人注册了回调函数:%X, 地址:%p}", TAGA, *gSendEvent, gSendEvent);
return 0;
}
void doing() {
gSendEvent(E_EVENT_DOING, "进行中..."); // 调用方式1
Sleep(1000);
}
void runA() {
LOGI("%s{我是A}", TAGA);
if (gSendEvent == NULL) {
LOGW("%s{B不关心我}", TAGA);
return;
}
(*gSendEvent)(E_EVENT_START, "我开始了哟"); // 调用方式2
doing();
(*gSendEvent)(E_EVENT_FINISH, "我好了");
}
// B的实现
#define TAGB "[MODULE_B]"
long long int gAStart = 0;
long long int gAFinish = 0;
void eventStartHandler(char *data) {
gAStart = GetTickCount();
LOGI("%s{A:%s}{%lld}", TAGB, data, gAStart);
}
void eventDoingHandler(char *data) {
LOGI("%s{A:%s}", TAGB, data);
}
void eventFinishHandler(char *data) {
long long int aDurS = 0;
gAFinish = GetTickCount();
LOGI("%s{A:%s}{%lld}", TAGB, data, gAFinish);
aDurS = (gAFinish - gAStart)/1000;
LOGI("%s{A %llds}", TAGB, aDurS);
if (aDurS < 10) {
LOGI("%s{A 真快}", TAGB);
}
}
void onEvent(EnumEvent type, char *data) {
switch (type) {
case E_EVENT_START:
eventStartHandler(data);
break;
case E_EVENT_DOING:
eventDoingHandler(data);
break;
case E_EVENT_FINISH:
eventFinishHandler(data);
break;
default:
break;
}
}
void careA() {
LOGI("%s{我的回调函数地址:%p}", TAGB, onEvent);
regEventCbk(onEvent);
}
void runB() {
LOGI("%s{我是B}", TAGB);
careA();
}
int main() {
LOGI("{start}");
runB();
runA();
return 0;
}
运行结果
可优化点
.文章来源:https://www.toymoban.com/news/detail-418831.html
参考博客
[1] https://zhuanlan.zhihu.com/p/162578969
[2] https://blog.csdn.net/zhou8201/article/details/100700479
[3] https://blog.csdn.net/qq_31300101/article/details/130190026?spm=1001.2014.3001.5502文章来源地址https://www.toymoban.com/news/detail-418831.html
到了这里,关于理解函数指针和回调函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!