zoukankan      html  css  js  c++  java
  • 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/
  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/oasisyang/p/14423422.html
Copyright © 2011-2022 走看看