c语言 ,回调函数[个人理解]
回调函数:把需要调用的方法的指针pCallBackFuncX作为参数传递给一个函数UsrFunction,以便该UsrFunction函数在处理相似事件的时候可以灵活的使用不同的方法。
以在flash中存储有序的交易记录为例:
交易记录列表内容如下所示,我们要对其排序然后存储到flash当中去。这个排序函数写作: int SortReclist(RECLIST_ST * reclist);
typedef struct {
char cityCode[] ; //城市代码 + 应用序列号
char usrName[];
unsigned char tradeTime[]; //交易时间【bcd】 年 月 日 时 分 秒
unsigned char TerminalCode[]; //终端硬件序列号
unsigned char reserve[];
} RECS_ST ;//交易记录 typedef struct {
unsigned char count[] ;
unsigned char max[] ;
unsigned char data[N_MAX_RECORD][SIZE_OF_RECS];// sizeof(RECS_ST); //要对这里的数据进行排序、去重。
unsigned char check ;
} RECLIST_ST;//交易记录列表
我们使用冒泡排序的方法对其中的数据进行排序,我们得到一组无序数据,我们不知道这组数据有多少个数据项、一个数据项多大、怎么比较他们的大小、如何交换数据项的位置。
我们可以设计如下,我们需要传入的参数不仅是数据p_data_in、n_elements、element_size,还有方法cmp_func、mem_swap:
bubble_sort(void* p_data_in , //pointer to data to sort 待排列的数据
int n_elements , //number of elements 待排列的数据个数
int element_size, //size of each element == sizeof(RECS_ST) 数据宽度
(CALLBACK_AFC_DATA_CMP) cmp_func , //cmp_func: pointer to comparison function 判定其排列次序的方法,这个是根据需要变换的。
(CALLBACK_MEM_SWAP) mem_swap) ; //mem_swap: pointer to swap function or NULL 内存交换的方法
typedef void (*CALLBACK_MEM_SWAP)(void *, void *, int n_bytes) ;
typedef int (*CALLBACK_AFC_DATA_CMP)(const void *, const void *) ;
bubble_sort的实现如下:
//ret==1: error
//ret==0: ok
int bubble_sort(void *base , //pointer to data to sort
int n_elements , //number of elements
int size_element , //size of each element
CALLBACK_AFC_DATA_CMP cmp_func ,//cmp_func: pointer to comparison function
CALLBACK_MEM_SWAP mem_swap )//mem_swap: pointer to swap function or NULL
{
int i, j, flag , cmp ;
if( base==0 || cmp_func==0 || mem_swap==0 ){
return 1 ;
} for (i=0; i<n_elements-1; i++)
{
flag = 0;
for (j=0; j<n_elements-1-i; j++)
{
cmp = cmp_func( ((char *)base+size_element*j ) , ((char *)base+size_element*(j+1)) ) ;
if ( cmp > 0 )
{
mem_swap( ((char *)base+j*size_element) , ((char *)base+(j+1)*size_element) , size_element );
flag = 1;
}
}
if ( !flag ) {
break ;
}
}
return 0;
}
int SortReclist(RECLIST_ST * reclist)
{
int ret;
unsigned char count[]; do{
memcpy(count , reclist->count , sizeof( count )); //这里是解决mdk对外部全局变量不能正确强转的解决办法,无视 bubble_sort(reclist->data , //pointer to data to sort
*(signed short*)count , //number of elements
sizeof( RECS_ST ) , //size of each element
(CALLBACK_AFC_DATA_CMP) reclistcmp , //cmp_func: pointer to comparison function
(CALLBACK_MEM_SWAP)mem_swap) ; //mem_swap: pointer to swap function or NULL
//暂且无视排序中去重的需求
}while(ret!=) ; return ;
}
到底采用何种方式来判断数据的大小,就根据实际需要了。下面是一个实现,只比较城市代码:
int reclistcmp(char *before ,char *next )
{
int ret ;
ret = memcmp(before ,next , ); //citycode[2] 简单判定
return ret ;
}
好处是,以回调函数的方式,在写主体框架时,可以不用知道某种功能的具体实现,而只是提出这个需求。
【写框架的人并不是完全不关心具体实现,不合理的框架设计导致具体功能无法按照给定的接口来实现。】
这样在处理具体业务时有更高的灵活性,这个功能的具体实现甚至可以交给其他人去完成。
//-----------------------------------------------------------------------------------------------------------------------------------------------//
另外,linux设备驱动函数注册也是回调的思想。linux内核并不知道我们具体设备的操作方式,它是这样对设备进行操作的,先规定操作函数的形式:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);//指定函数接口形式
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
};
然后驱动设计者按照规定的形式实现ioctl。
/* 应用程序对设备文件/dev/leds执行ioctl(...)时,
* 就会调用s3c24xx_leds_ioctl函数
*/
static int s3c24xx_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,//ON / OFF
unsigned long arg)//n_led
{
if (arg > ) {
return -EINVAL;
} switch(cmd) {
case IOCTL_LED_ON:
// 设置指定引脚的输出电平为0
s3c2410_gpio_setpin(led_table[arg], );
return ; case IOCTL_LED_OFF:
// 设置指定引脚的输出电平为1
s3c2410_gpio_setpin(led_table[arg], );
return ; default:
return -EINVAL;
}
}
驱动设计者再注册操作集,包括了ioctl。
static struct file_operations s3c24xx_leds_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = s3c24xx_leds_open,
.ioctl = s3c24xx_leds_ioctl,
}; //in moudle_init:
ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
这样,在打开操作设备时,系统使用到了驱动设计者的设备操作方法。
扩展阅读:
1.回调机制
http://blog.sina.cn/dpool/blog/s/blog_77c632410101cjty.html
回调实现分层设计。
http://blog.chinaunix.net/uid-21222282-id-1829257.html
c语言 ,回调函数[个人理解]的更多相关文章
- 对c语言回调函数的理解
对于回调函数,可以简单的理解为一种特别的函数调用方法,我们可以对比一下回调函数与普通函数在调用方法上的区别. 1. 普通函数调用 一般为实现方在其函数体执行过程中直接调用. 代码示例: #includ ...
- js回调函数(callback)理解
Mark! js学习 不喜欢js,但是喜欢jquery,不解释. 自学jquery的时候,看到一英文词(Callback),顿时背部隐隐冒冷汗.迅速google之,发现原来中文翻译成回调.也就是回调函 ...
- js回调函数的理解
js回调函数(callback)理解 Mark! 讲之前说一句 function say(){ alert(,,,,,,,,) } var say=function (){ alert(,,,,,,, ...
- 回调函数透彻理解Java
http://blog.csdn.net/allen_zhao_2012/article/details/8056665 回调函数透彻理解Java 标签: classjavastringinterfa ...
- js中的回调函数的理解和使用方法
js中的回调函数的理解和使用方法 一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为 ...
- JavaScript callback function 回调函数的理解
来源于:http://mao.li/javascript/javascript-callback-function/ 看到segmentfault上的这个问题 JavaScript 回调函数怎么理解, ...
- 转·带你用实例理解C语言回调函数
原文出处:https://segmentfault.com/a/1190000008293902?utm_source=tag-newest 前言: 如不懂函数指针,请先查阅关于函数指针内容的资料(h ...
- 对于Python中回调函数的理解
关于回调函数,网上有很多说明和各种解释,多数在尝试用语言描述.我认为,如果对各个角色之间的关系不清楚,如果没有相关的编程需求,那么语言便非常无力,很难理解. 这是360百科的解释: 在计算机程序设计中 ...
- C语言回调函数详解
1. 什么是回调函数? 回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义.我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用类 ...
随机推荐
- checkbox、select、radio的设置与获取
参考链接:http://www.cnblogs.com/xiaopin/archive/2011/09/13/2175190.html js版本: <!DOCTYPE html PUBLIC & ...
- Symfony命令行
Available commands: help 显示命令的帮助信息 list ...
- yii教程
http://www.yiichina.com/doc 官网是很好的参考文档
- Lotus Sametime 服务器的安装和配置
IBM Lotus Sametime 是一款强大的实时协作软件,目前最新版本是 7.5.1.通过它,您不仅能够进行网络聊天,而且可以方便地召开网络会议.在网络社区中与其他人进行沟通.了解更多关于 Lo ...
- 转;说说AngularJS中的$parse和$eval
说说AngularJS中的$parse和$eval AngularJS的初学者常常会对$parse和$eval两个内建服务感到有些困惑,今天我们就来说说AngularJS中的$parse和$eval. ...
- [学习笔记]jQuery实现一些动画效果的方法
jQuery实现效果的方法 1,隐藏和显示:hide(),show(),toggle() // [ˈtɑ:gl]切换 语法: $(selector).hide(speed,callback); $( ...
- TextBox控件只允许输入出生日期,并验证年龄不得小于18岁
1.Body tag <form id="form1" runat="server"> <div> <asp:Label ID=& ...
- 自定义cell相关注意事项
1.拖线成功后,如果又在.h文件或者.m文件里面删除了对应的属性或者方法.一定要在xib文件中,删除关联.方法是:右键点击一下对应的UI控件,把多余的关联叉掉就行了. 不然容易崩溃.
- Task线程 同时执行多个任务
Task taskTest = Task.Factory.StartNew(() => { Console.WriteLine("); },TaskCreationOptions.No ...
- DLL运行时动态加加载的问题
1.error C2440: 'initializing' : cannot convert from 'int (__stdcall *)(void)' to 'void (__cdecl *)(c ...