理解函数指针

指向函数的指针。比如:

理解函数指针的伪代码
void (*p)(int type, char *data); // 定义一个函数指针pvoid func(int type, char *data); // 声明一个函数funcp = func; // 将指针p指向函数funcp(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 #include // 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, "进行中..."); // 调用方式1Sleep(1000);}void runA() {LOGI("%s{我是A}", TAGA);if (gSendEvent == NULL) {LOGW("%s{B不关心我}", TAGA);return;}(*gSendEvent)(E_EVENT_START, "我开始了哟"); // 调用方式2doing();(*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;}

运行结果

可优化点

.

参考博客

[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