理解函数指针和回调函数

yizhihongxing

理解

函数指针

指向函数的指针。比如:

理解函数指针的伪代码
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;
}

运行结果

image

可优化点

.

参考博客

[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.cnblogs.com/livetime/p/17335033.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:理解函数指针和回调函数 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月22日

相关文章

  • C++实现对RGB图片进行编码的示例代码

    首先,对于RGB图片的编码,我们需要将RGB颜色空间中的每个像素点转换为对应的YUV颜色空间中的亮度值Y和色度值U、V。这一步可以通过计算公式进行:Y = 0.299R + 0.587G + 0.114B,U = 0.492(B – Y),V = 0.877(R – Y),其中R、G、B分别是像素点在RGB颜色空间中的红、绿、蓝值。 示例代码1:将RGB图片…

    C 2023年5月24日
    00
  • 深入理解C/C++混合编程

    深入理解C/C++混合编程 混合编程是指在C/C++程序中调用其他语言编写的模块,例如Python、Java等。在C/C++中实现混合编程有多种方法,本文将详细讲解其中的两种常见方法。 方法1:使用C++的Extern-C机制 C++支持Extern-C机制,能够将C++代码转化为类似于C的代码,从而实现C/C++混合编程。具体操作步骤如下: 使用C++编写…

    C 2023年5月23日
    00
  • 详解C语言随机数设置的三种方式(保姆级教程)

    首先我们来详细讲解下“详解C语言随机数设置的三种方式(保姆级教程)”这篇文章。 详解C语言随机数设置的三种方式(保姆级教程) 一、问题背景 在开发C语言程序时,我们经常需要使用到随机数。掌握如何设置C语言随机数生成器,可以帮助我们更好地编写程序。本文就C语言随机数设置的三种方式进行详细解析,并且提供示例代码和执行结果。 二、三种方式 1. 随机数发生器初始化…

    C 2023年5月22日
    00
  • C++ 迷宫游戏实现代码

    关于“C++ 迷宫游戏实现代码”的完整攻略,我可以为您提供以下几点建议和示例说明: 一、基本思路 实现迷宫游戏,基本思路可以分成两个步骤: 生成迷宫地图 玩家游戏交互 生成迷宫地图可以采用递归回溯算法,即先随机生成一张完全闭合的迷宫地图,再从某个随机位置开始不断试探,打通墙壁,直到所有墙壁都被打通,形成一张通畅的迷宫地图。 玩家游戏交互则可以使用键盘输入控制…

    C 2023年5月24日
    00
  • Python列表嵌套常见坑点及解决方案

    下面就是对“Python列表嵌套常见坑点及解决方案”的详细讲解。 1. 什么是Python列表嵌套? Python中的列表是一种可以存储多个元素的数据结构,而列表嵌套则是指把一个或多个列表作为元素存储在另一个列表中。例如,以下是一个简单的列表嵌套的示例: nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 以上示例…

    C 2023年5月22日
    00
  • MongoDB导出查询结果到文件例子

    MongoDB导出查询结果到文件主要有两种方式:使用mongoexport命令和使用db.collection.find().forEach()方法,下面分别进行讲解: 使用mongoexport命令导出查询结果到文件 语法: mongoexport -d <database_name> -c <collection_name> -q…

    C 2023年5月23日
    00
  • C语言实现简单的推箱子游戏

    C语言实现简单的推箱子游戏攻略 游戏规则 推箱子游戏是一款智力类游戏,玩家需要通过推动木箱到指定的位置来完成游戏,游戏难度逐渐增加。 游戏规则如下: 玩家可以通过键盘上的 ↑、↓、←、→ 控制人物(P)的移动,人物可以向四个方向行走; 如果人物面对着一个箱子(O),玩家按下操作键,木箱就会朝着人物所面对的方向移动一个格子; 箱子在游戏界面移动的过程中,必须始…

    C 2023年5月23日
    00
  • C++实现学生考勤信息管理系统

    C++实现学生考勤信息管理系统 系统需求 首先,我们需要定义考勤信息管理系统的需求: 能够添加新学生记录; 能够删除指定学生记录; 能够显示所有学生记录; 能够修改指定学生记录; 能够查询指定学生记录。 数据结构设计 为了实现学生考勤信息管理系统,我们需要定义数据结构来存储学生记录。这里我们选择使用结构体来表示一个学生记录,包括以下字段: struct St…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部