理解函数指针和回调函数

理解

函数指针

指向函数的指针。比如:

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

相关文章

  • Visual Studio Code (vscode) 配置C、C++环境/编写运行C、C++的教程详解(Windows)【真正的小白版】

    Visual Studio Code (vscode) 配置C、C++环境/编写运行C、C++的教程详解(Windows)【真正的小白版】 本文将会为大家介绍如何在Windows平台下,使用Visual Studio Code(以下简称vscode)进行C、C++的编写和运行。在本教程中,我们假设我们从零开始,仅具备基本的计算机知识,因此我们将尽可能详细地给…

    C 2023年5月23日
    00
  • JS 实现Json查询的方法实例

    JS 实现JSON查询的方法实例 在项目中,我们常常需要通过给定的条件查询数据。如果数据存储在JSON格式的文件中,我们可以使用JS实现JSON查询。下面是JS实现JSON查询的方法实例。 1. 获取JSON数据 首先,我们需要获取JSON数据。这可以是从服务器或本地文件中获取。在本例中,我们将使用本地文件。我们可以使用XMLHttpRequest对象获取J…

    C 2023年5月23日
    00
  • C语言实现贪吃蛇游戏代码

    C语言实现贪吃蛇游戏代码 简介 贪吃蛇是一种经典的游戏,我们可以使用C语言来实现这个游戏。在这个游戏中,蛇在一个二维平面上移动,吃掉食物来增加长度,如果蛇触碰到了自己或者墙壁,那么游戏就结束了。 实现过程 下面是用C语言实现贪吃蛇游戏的步骤: 定义游戏中的基本元素,如蛇、食物、地图等。 初始化游戏元素,包括蛇的初始位置、长度和方向,食物的随机位置。 创建游戏…

    C 2023年5月23日
    00
  • 探究c++虚表实现代码

    探究 C++ 虚表的实现代码是一个相当深入的话题,需要对 C++ 对象模型以及函数调用机制有一定的了解。下面将介绍如何进行这样一个的探究,包括以下的几个部分: 对 C++ 对象模型的介绍 虚表的定义和用途 虚表的实现方式 通过示例说明虚表的使用和作用 对 C++ 对象模型的介绍 在了解虚表实现之前,我们需要先了解 C++ 对象模型。C++ 对象模型指的是 C…

    C 2023年5月23日
    00
  • C语言实现病例管理系统

    C语言实现病例管理系统攻略 1. 简介 病例管理系统是医院或诊所等医疗机构常用的一种信息管理系统,通过该系统能够快速有效地管理病人的基本信息、病史以及药物处方等。这需要使用到C语言的数据类型、字符串操作等基本操作,实现起来比较简单。 2. 实现流程 2.1 确定需求 首先,我们需要明确病例管理系统需要具备哪些功能,如:添加病例、删除病例、修改病例、查询病例等…

    C 2023年5月23日
    00
  • js 转json格式的字符串为对象或数组(前后台)的方法

    要将 JS 转成 JSON 格式的字符串为对象或数组,有两种常见的方法,分别是: 1.使用 JSON.parse() 将 JSON 字符串转换为对象或数组; 2.使用 eval() 函数将 JSON 字符串转换为对象或数组。 下面我们分别来讲解这两种方法的使用方法及示例说明。 1.使用 JSON.parse() 转换成对象或数组JSON.parse() 方法…

    C 2023年5月23日
    00
  • C 头文件

    下面详细讲解一下 C 头文件的完整使用攻略。 什么是 C 头文件 在 C 语言中,头文件是一种特殊的文件,它包含了一些函数和变量的声明,可以被其他源文件引用。头文件的作用就是让代码更好维护和组织,可以将程序中的一些常用的函数和变量声明都放在头文件中,便于管理和使用。 如何使用 C 头文件 C 头文件通常包含两个部分:宏定义和函数声明。其中,宏定义是用来定义一…

    C 2023年5月10日
    00
  • 神乐千鹤在拳皇97、98中的高级用法

    神乐千鹤在拳皇97、98中的高级用法攻略 什么是神乐千鹤? 神乐千鹤是拳皇系列游戏中的一位角色,拥有快速的移动速度和敏捷的攻击方式。她在拳皇97和98中的操作难度较高,但是如果掌握了她的高级用法,就可以轻松地击败对手。 神乐千鹤的高级用法 1. 投掷连击 神乐千鹤的投掷连击是一种非常强大的攻击方式。要进行投掷连击,首先需要进行一次投掷攻击(按下前+C),然后…

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