理解
函式指標
指向函式的指標,比如:
理解函式指標的偽代碼
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
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/550538.html
標籤:其他