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. 什么是回调函数? 回调函数,光听名字就比普通函数要高大上一些,那到底什么是回调函数呢?恕我读得书少,没有在那本书上看到关于回调函数的定义.我在百度上搜了一下,发现众说纷纭,有很大一部分都是使用类 ...
随机推荐
- mysql 查询条件中文问题
这是mysql字符编码的问题,因为mysql默认的字符编码为latin1它并不识别中文,所以在读取查询语句时会出现乱码 从而使查询条件不正确所以我们只需要更改它的字符编码就可以一般都是用utf8 这里 ...
- elk 分布式数据同步
zjtest7-redis:/elk/elasticsearch/data/es_cluster/nodes/0/indices/library# strings ./1/index/_3.cfs | ...
- PHP移动互联网开发(1)——环境搭建及配置
原文地址:http://www.php100.com/html/php/rumen/2014/0326/6702.html 一.PHP5.4环境搭配基本流程 Apache:Web服务提供者.官网:ww ...
- Objective-c 类实现 (@implementation)
在用@interface声明类之后,可以使用@implementation进行实类的实现.类的实现的具体语法如下: @implementation 类名 方法实现代码; @end; 实例: @impl ...
- hdu4300之KMP&&EKMP
Clairewd’s message Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- java 构造函数是如何执行的
1.构造函数不是方法!! 原因1:方法的话,会直接执行方法体内的代码,但是构造函数首先执行的不是{}里的代码块,而是给对象的成员初始化: 2.方法可以被调用其他方法调用,但是构造函数不能被方法或变量调 ...
- js中使用this的一些注意事项
先看看这段代码 var x =9; var fobj ={ x:1, test:function(callback){ var x= 2; callback(); } } function pp(){ ...
- 用jmeter进行多用户并发压力测试 [转]
近日manager要求对项目进行压力测试,开始对jmeter进行了研究.jmeter是Apache一个开源项目,可对各种项目进行测试,甚至包括junit. 测试要求如下,多用户同时登陆web应用程序, ...
- r语言之给定的概率密度函数生成随机数
假设概率密度函数为: 思路: 首先产生-1到1之间的均匀分布随机数x,和0到1之间的均匀分布随机数y. 如果y<f(x),则x是符合该概率密度的随机数,否则,重复上述操作. 用r语言生成100个 ...
- OC中的类型强制转换
在Objective-C中,以数字格式组成的字符串经常需要转换为NSNumber对象后再使用.例如有一个字符串对象@"111.22",需要转为NSNumber对象,最简单的方法就是 ...