• typesafe_cb


    callback 回调函数

    什么是callback function

    如图(来自维基百科),回调函数提供了一种服务,可以由用户决定使用怎么样的服务(登记回调函数)。回调函数机制,提供了很大的灵活性,可以将库函数视为中间函数,借用回调函数完成个性化的服务。本文下面的内容会使用到ccan中的一个安全回调函数库。

    typesafe_cb.h

    版权:

    License: CC0 (Public domain)
    Author: Rusty Russell <rusty@rustcorp.com.au>
    

    该头文件是为实现安全的回调函数所编写的一系列的宏,包括

    作者在_info文件中写道:

    If an expression exactly matches a given type, it is cast to the target type, otherwise it is left alone.
    

    其根本目的在于,避免强制使用void*指针破坏类型检查。

    typesafe_cb_cast

    /*
     * 当表达式匹配给定类型时,进行类型转换
     * dest_t:目标类型
     * allow_t : 允许的类型
     * expr : 需要转换类型的表达式
     */
    #define typesafe_cb_cast(dest_t, allow_t, expr)			
    	__builtin_choose_expr(						
    		__builtin_types_compatible_p(__typeof__(0?(expr):(expr)), 
    					     allow_t),			
    		(dest_t)(expr), (expr))
    

    此处使用了两个GNU扩展

    int __builtin_types_compatible_p(type_a,type_b)
    

    如果类型相同返回1否则返回0

    type __builtin_choose_expr(const_expr,expr_a,expr_b)
    

    如果常量表达式值非0,则生成expr_a,否则生成expr_b。 这都是编译期行为。

    这两个扩展的结合,可以一定程度实现泛型编程。

    因此这个宏typesafe_cb_cast的功能便很显然了。

    由此产生的相关宏如下:

    /*
     * 三种允许的类型,typesafe_cb_cast 的三重嵌套
     */
    #define typesafe_cb_cast3(dest_t,allow_t1,allow_t2,allow_t3,expr) 
            typesafe_cb_cast(dest_t,allow_t1,                         
                            typesafe_cb_cast(dest_t,allow_t2,         
                                            typesafe_cast(dest_t,allow_t3,(expr))))
    

    typesafe_cb

    /*
     * 如果回调函数参数匹配就进行类型转换
     * @ret_t: 回调函数返回值类型
     * @exp_t: 回调函数期待的(指针)类型
     * @func: 需要类型转换的回调函数
     * @arg: 传给回调函数的参数
     */
    #define typesafe_cb(ret_t,exp_t,func,arg) 
            typesafe_cb_cast(ret_t(*)(exp_t), 
                             ret_t(*)(__typeof__(arg)), 
                             (func))
    

    此处调用的 typesafe_cb_cast中的类型为函数指针

    ret_t(*)(exp_t) :指向返回值为ret_t类型,参数为exp_t类型的函数的函数指针
    

    这个宏在函数只有一个参数传入时能很好的工作。

    if typeof(func)==ret_t(*)(__tyoeof__(arg))
    then typeof(func)--->ret_t(*)(exp_t)
    

    typesafe_cb_preargs

    /*
     * 对于有多个参数的函数,针对的是在arg之前有多个参数
     * 比如 void(*fn)(int,void*arg)
     */
    #define typesafe_cb_preargs(rtype, atype, fn, arg, ...)			
    	typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype),			
    			 rtype (*)(__VA_ARGS__, __typeof__(arg)),	
    			 (fn))
    

    仅仅是用了变参宏从而扩展了多参数回调函数的情况,举个例子

    void _register_callback(void (*fn)(int, void *arg), void *arg);
    #define register_callback(fn, arg)				   					
     		_register_callback(typesafe_cb_preargs(						
    							void, void *,(fn), (arg), int),			
     				   (arg))
    

    在这个例子中:

    ret_t :void
    allow_t: void*
    fn:		void (*fn)(int, void *arg)
    arg:    (arg)
    ...:    int
    

    那么对于多的参数在arg之后也就有相应的情况了

    #define typesafe_cb_postargs(rtype, atype, fn, arg, ...)		
    	typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__),			
    			 rtype (*)(__typeof__(arg), __VA_ARGS__),	
    			 (fn))
    

    应用

    ccan_info中,作者给出了这样一个例子

    #include "typesafe_cb.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    /*callback函数链*/
    struct callback{
    	struct callback *next;
    	int value;
    	int(*callback)(int value,void *arg);
    	void *arg;
    };
    
    static struct callback *callbacks;
    
    /*给定值与参数注册回调函数*/
    static void _register_callback(int value,int(*cb)(int,void*),void *arg)
    {
    	struct callback *new=malloc(sizeof(*new));
    	new->next=callbacks;
    	new->value=value;
    	new->callback=cb;
    	new->arg=arg;
    	callbacks=new;
    }
    
    /*
     * exp_t:int(*)(__VA_ARGS__,void*)
     * allow_t:int(*)(__VA_ARGS__,__typeof__(arg))
     */
    #define register_callback(value,cb,arg)
    	_register_callback(value,
    			typesafe_cb_preargs(int ,void*,(cb),(arg),int),(arg))
    
    /*通过value,查找callback函数*/
    static struct callback *find_callback(int value)
    {
    	struct callback * i;
    	for(i=callbacks;i;i=i->next){
    		if(i->value==value){
    			return i;
    		}
    	}
    	return NULL;
    }
    
    /* 定义回调函数的宏,注意此处并没有用void*指针
     * 回调函数的类型
     * int(*cb)(int,int*arg)
     * */
    #define def_callback(name,op)
    	static int name(int val,int *arg)
    	{
    		printf("%s",#op);
    		return val op *arg;
    	}	
    
    def_callback(multiply,*);
    def_callback(add, +);
    def_callback(divide, /);
    def_callback(sub, -);
    def_callback(or,|);
    def_callback(and,&);
    def_callback(xor, ^);
    def_callback(assign, =);
    
    int main(int argc,char*argv[])
    {
    	int i,run=1,num= argc > 1 ? atoi(argv[1]) : 0 ;
    	for (i = 1; i < 1024;) {
            /*
             * replacement: _register_callback(i++, (int (*)(int, void *)) (((add))), (&run))
             * exp_t:   int (*)(int, void *)
             * allow_t: int (*)(int,__typeof__(arg))--->int (*)(int,int*)
             * cb_t:    int (*)(int,int*)
             */
     			register_callback(i++, add, &run);
     			register_callback(i++, divide, &run);
     			register_callback(i++, sub, &run);
     			register_callback(i++, multiply, &run);
     			register_callback(i++, or, &run);
     			register_callback(i++, and, &run);
     			register_callback(i++, xor, &run);
     			register_callback(i++, assign, &run);
     		}
    
     		printf("%i ", num);
     		while (run < 56) {
     			struct callback *cb = find_callback(num % i);
     			if (!cb) {
     				printf("-> STOP
    ");
     				return 1;
     			}
     			num = cb->callback(num, cb->arg);
     			printf("->%i ", num);
     			run++;
     		}
     		printf("-> Winner!
    ");
     		return 0;
    }
    
    

    参考

    1. http://ccodearchive.net/
  • 相关阅读:
    Multidimensional Arrays
    TortoiseGit
    Excel教程(14)
    Excel教程(13)
    Excel教程(12)
    Excel教程(11)
    lock
    reflect
    game
    html x
  • 原文地址:https://www.cnblogs.com/oasisyang/p/14423422.html
Copyright © 2020-2023  润新知