理解 函數指針 指向函數的指針。比如: 理解函數指針的偽代碼 void (*p)(int type, char *data); // 定義一個函數指針p void func(int type, char *data); // 聲明一個函數func p = func; // 將指針p指向函數func ...
理解
函數指針
指向函數的指針。比如:
理解函數指針的偽代碼
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;
}
運行結果
可優化點
.
參考博客
[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