c语言 ,回调函数[个人理解]

回调函数:把需要调用的方法的指针pCallBackFuncX作为参数传递给一个函数UsrFunction,以便该UsrFunction函数在处理相似事件的时候可以灵活的使用不同的方法。

 

 

以在flash中存储有序的交易记录为例:

交易记录列表内容如下所示我们要对其排序然后存储到flash当中去。这个排序函数写作: int SortReclist(RECLIST_ST * reclist);

typedef struct {
    char cityCode[2] ;            //城市代码 + 应用序列号
    char usrName[10];
    unsigned char tradeTime[7];      //交易时间【bcd】 年 月 日 时 分 秒
    unsigned char TerminalCode[6];   //终端硬件序列号
    unsigned char reserve[1];
} RECS_ST ;//交易记录

typedef struct {
    unsigned char count[2] ;
    unsigned char max[2] ;
    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[2]; 
    
    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!=0) ;

    return 0;
}  

到底采用何种方式来判断数据的大小,就根据实际需要了。下面是一个实现,只比较城市代码:
int reclistcmp(char *before ,char *next ) 
{
    int ret ;
    ret = memcmp(before ,next , 2);  //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 > 4) {
        return -EINVAL;
    }

    switch(cmd) {
    case IOCTL_LED_ON:
        // 设置指定引脚的输出电平为0
        s3c2410_gpio_setpin(led_table[arg], 0);
        return 0;

    case IOCTL_LED_OFF:
        // 设置指定引脚的输出电平为1
        s3c2410_gpio_setpin(led_table[arg], 1);
        return 0;

    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

2.简单的c++回调函数设计方法(一)  

  回调实现分层设计。

  http://blog.chinaunix.net/uid-21222282-id-1829257.html

posted @ 2014-11-20 14:17  oucaijun  阅读(724)  评论(0编辑  收藏  举报
下载TeamViewer完整版 下载TeamViewer