C高级——回调函数
2017-03-03 00:00
120 查看
回调的实质:
其实回调就是一种利用函数指针进行函数调用的过程。 函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。回调的基本使用思想是,如果你有一个对数的操作,你现在还不知道是对它做加还是乘,还是别的什么运算。这个时候就可以定一个标准的函数框架,在调用的时候,将我要用的那个函数名作为参数传入,则进行相应的操作。
回调的实现:
/* * 这是一个简单的回调函数示例 * 当我想预留操作接口的时候,通过typedef定义回调函数 */ #include <stdio.h> typedef int (* operation)(int i,int j); //通过typedef定义回调函数 int plus(int i,int j){ printf("%s: ",__FUNCTION__ ); return i + j; } int minus(int i,int j){ printf("%s: ",__FUNCTION__ ); //__FUNCTION__为函数宏,此句会输出本函数名 return i - j; } int opr_cb(int i,int j,operation cb){ return cb(i,j); } int main(){ operation cb = plus; //利用回调函数名创建回调函数,并赋值 printf("%d\n",opr_cb(3,5,cb)); //调用回调函数,cb为函数名;也可以直接使用plus或minus作为参数传递 return 0; } /* * 输出结果: * 当cb赋值为plus时,输出:"plus: 8"; * 当cb赋值为minus时,输出:"minus: -2"; */
回掉的应用:
1、消息、事件处理。事件程序监测事件,同时维护一个回调函数列表,当有事件发生的时候发给所有注册的函数。直接实现是同步调用的,注册回掉是一种异步调用的关系。2、预留接口。在模块设计的时候,知道要对数据做操作,但又不知道具体是什么操作,提供一个callback的接口,由用户实现具体的操作。
/* * 这是一个简单的事件推送示例 * 事件检测程序负责检测是否有事件发生 * 主程序维护一个事件的回掉注册表,当有事件发生的时候,将消息发送给所有注册的回掉程序 */ #include "stdio.h" #include "unistd.h" #include "stdlib.h" #include "string.h" #include "pthread.h" #include "sys/time.h" enum Boolean{ false = 0, true = (!false) }; typedef enum //事件类型,可以根据自己的需要而添加 { T_NOTICE = 0, T_TIME = 1 }event_type; typedef struct //事件消息定义 { event_type type; union{ char txt[200]; time_t time; }content; //两类消息,对应的有自己的数据类型 }event_msg; event_msg g_msg; volatile static event_flag = false; typedef void (*event_cb)(event_msg *msg); //回调申明 unsigned int event_num = 0; //MAX值此处未定义 typedef struct event_factory //回调函数的注册 { event_cb cb; struct event_factory *next; }EVENT_FACTORY; EVENT_FACTORY event_head; int event_factory_init() //初始化注册表头 { memset(&event_head,0,sizeof(event_head)); event_head.cb = NULL; event_head.next = NULL; return true; } int event_factory_insert(event_cb cb) //注册表注册函数 { if(cb == NULL) return false; EVENT_FACTORY *new = NULL,*tmp = NULL; if(event_num == 0) { event_head.cb = cb; } else { new = malloc(sizeof(EVENT_FACTORY)); memset(new,0,sizeof(EVENT_FACTORY)); new->cb = cb; new->next = NULL; tmp = &event_head; while(tmp->next != NULL) tmp = tmp->next; tmp->next = new; } event_num++; return true; } int event_factory_delete(void) //注册表回收函数 { EVENT_FACTORY *tmp,*now=&event_head; while(now->next != NULL) { tmp = now; now = now->next; free(tmp); } return true; } static void UI_process(event_msg *msg) //模拟UI处理线程 { switch(msg->type) { case T_NOTICE: printf("%s, %s\n", __FUNCTION__, (char *) &msg->content); break; case T_TIME: printf("%s, Display %d\n", __FUNCTION__, *(int*)&msg->content.time); break; default: printf("%s, event_type error\n", __FUNCTION__); break; } } static void Music_process(event_msg *msg) //模拟音乐播放器处理线程 { switch(msg->type) { case T_NOTICE: printf("%s, %s\n",__FUNCTION__, (char *) &msg->content); break; case T_TIME: printf("%s, jump\n",__FUNCTION__); break; default: printf("%s, event_type error\n", __FUNCTION__); break; } } static void* event_process(void* data) //模拟事件响应,不同进程使用消息队列来发送消息 { struct timeval tv; struct timezone tz; while(1){ while(event_flag == true) sleep(0.2); printf("check get T_NOTICE\n"); //while(get_notice()); memset(&g_msg, 0, sizeof(g_msg)); g_msg.type = T_NOTICE; strncpy(g_msg.content.txt,"test",sizeof(g_msg.content.txt)); event_flag = true; sleep(2); while(event_flag == true) sleep(0.2); printf("check get T_TIME\n"); //while(get_time()); memset(&g_msg, 0, sizeof(g_msg)); g_msg.type = T_TIME; gettimeofday(&tv, &tz); g_msg.content.time = tv.tv_sec; event_flag = true; sleep(2); } pthread_exit(0); } int main() { int i = 0; pthread_t event_thread; EVENT_FACTORY *tmp = NULL; event_factory_init(); event_factory_insert(UI_process); event_factory_insert(Music_process); if(0 != pthread_create(&event_thread, NULL, event_process, NULL)) { perror("event_thread create"); } while(1) { while(event_flag == false) sleep(0.2); tmp = &event_head; for(i = 0; i < event_num ; i++) { if(tmp->cb == NULL) continue; tmp->cb(&g_msg); tmp = tmp->next; } event_flag = false; printf("------------\n"); } if(0 !=pthread_join(event_thread,NULL)) perror("pthread_join"); event_factory_delete(); return 0; }
输出:
check get T_NOTICE UI_process, test Music_process, test ------------ check get T_TIME UI_process, Display 1504685499 Music_process, jump ------------ check get T_NOTICE UI_process, test Music_process, test ------------ check get T_TIME UI_process, Display 1504685503 Music_process, jump ------------ 。。。。
总结:
除了这里列举的应用场景外,回调的使用场景还有很多,但都是对其本质的应用。所以理解了回调的本质,万变不离其宗。相关文章推荐
- Lua知识点_高级_c++中调用Lua回调函数
- 回调函数的高级用法
- 15 JS基础之--函数高级之回调函数
- 回调函数高级
- php函数高级部分【回调函数】
- JavaScript高级教程-第一课
- [Python]Socket高级 -- select I/O复用模型(一)
- iOS开发UI高级—33核心动画(基础动画)
- 如何成为一个C++高级程序员
- 高级绘图
- 第二部分 Linux Shell高级编程技巧——第三章 运行级别脚本介绍
- iOS开发UI高级—40popoverController简单介绍
- 阿里巴巴笔试整理系列 Session2 高级篇
- 表格高级使用技巧_把表格进行到底(必看)
- DirectX 3D_基础之HLSL(高级着色语言) HLSL着色器程序的编制 HSLS变量 HLSL入口函数 HLSL程序编译 变量常量类型 设置方法 前缀 关键字 类型 语句 类型转换
- PHP高级特性二之文件处理
- 线程高级应用-心得8-java5线程并发库中同步集合Collections工具类的应用及案例分析
- 引进软件国际标准,培养高级软件人才
- [置顶] java高级工程师--------hibernate的知识重点
- Swing高级JProgressBarTest进度条