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\n");
 				return 1;
 			}
 			num = cb->callback(num, cb->arg);
 			printf("->%i ", num);
 			run++;
 		}
 		printf("-> Winner!\n");
 		return 0;
}

参考

  1. http://ccodearchive.net/
posted @ 2021-02-20 21:31  OasisYang  阅读(102)  评论(0编辑  收藏  举报