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. 什么是回调函数? 回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义.我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用类 ...
随机推荐
- UVa1225 Digit Counting
#include <stdio.h>#include <string.h> int main(){ int T, N, i, j; int a[10]; sc ...
- Hadoop学习笔记(1)概述
写在学习笔记之前的话: 寒假已经开始好几天了,似乎按现在的时间算,明天就要过年了.在家的这几天,该忙的也都差不多了,其实也都是瞎忙.接下来的几点,哪里也不去了,静静的呆在家里学点东西.所以学习一下Ha ...
- 创建理想的SEQUENCE和自增长的trigger
SEQUENCE CREATE SEQUENCE TEST_SEQ START 1 --从1开始,第一个一定是NEXTVAL,因为第一个CURRVAL不好使,返回值会是1,第一个NEXTVAL相当于从 ...
- sping+maven+mybatis+ehcache续之实现mapper
配置接着上一篇文章 新建UserMapper.java和UserMapper.xml 其中UserMapper.xml的namespace以及文件名要和UserMapper.java一致 <ma ...
- 转;说说AngularJS中的$parse和$eval
说说AngularJS中的$parse和$eval AngularJS的初学者常常会对$parse和$eval两个内建服务感到有些困惑,今天我们就来说说AngularJS中的$parse和$eval. ...
- codeigniter IE浏览器下无法登录的解决的方法
站点搬迁到新的server后,CI 框架做的站点IE浏览器下无法登录.登录时候採用CI自带的SESSION机制,事实上是以COOKIE保存. 网上搜索到IE浏览器不支持域名存在- _. 不是这个原因, ...
- 转载 js判断浏览器
$scope.identifyBrowser= function () { var userAgent = navigator.userAgent, rMsie = /(msie\s|trident. ...
- asp.net中 服务器控件中onselectedindexchanged 没有反应的解决方案
最近发现项目中一个BUG就是 DropDownList 中的onselectedindexchanged 没有反应 AutoPostBack="true"和页面中的<%@ P ...
- iOS推送证书p12转成pem
首先你需要导出p12格式的证书,具体操作请参考如下: 其次你就可以通过在控制台输入如下命令即可转换: openssl pkcs12 -in 你导出的p12证书 -out 你要转换的pem证书 -nod ...
- linux基本命令-注销、关机、重起
链接地址:http://blog.163.com/bhao_home/blog/static/6647763120081202047945/ 一.注销,关机,重启 注销系统的logout命令 1,Lo ...