C - Wrapper Function

Wrapper function in C

很多解释型语言都提供了wrapper函数的功能,所谓wrapper函数就是修改原函数返回一个新函数,例如你想要为原函数添加/修改默认参数值,或者想要在原函数调用之前/后进行一些额外的处理,这些都可以通过wrapper函数来实现,并且很多解释型语言为此提供了装饰器这种快捷的wrapper方式,那么C语言可以实现wrapper的功能吗?

预备知识

在介绍wrapper功能在C语言中的实现之前,先来看看函数以及函数指针到底是什么东西?

函数的实质是存放于程序代码段的只读机器指令,而函数名记录了函数指令的入口地址,所以在C语言中的函数是可读不可写的。

只要有了函数的入口地址(而不是函数的整个指令内容)你可以对函数进行任意次引用,在C语言中函数入口地址的表示是使用指针来实现的,函数指针和普通指针变量是没有区别的,因为不管是void指针,函数指针,结构体指针都是使用若干字节(一般是4字节)来存放地址的,总之你要明白函数指针就是一个普通的指针而已

将函数作为参数传递的实质就是将函数入口地址复制到形参的过程,将函数作为参数传递的一般使用情形是,库开发者不了解用户在使用库时传入的数据细节,所以库开发者期望用户一并传入数据处理函数,例如要打算开发一个通用的排序函数,排序的最基本数据处理就是比较两个数据之间的大小,由于该函数是面向通用数据类型的,排序函数的开发者无法推测用户使用该函数时会传入什么类型的数据进行排序,所以开发者将排序中最基本的数据处理操作交给用户来实现(因为用户清楚自己待排序数据的细节),而将排序算法的框架留给开发者自己来实现,通过明晰的责任划分使得该代码的通用性得到了极大的提升,见下面的示例接口:

    void sort(void *data, int (*compare)(const void *data1, const void *data2);

上面提到函数名表示函数的入口地址,函数指针跟普通的指针是没有两样的,它们之间的唯一区别就是书写形式上的区别,声明函数指针变量int (*match)(const void *data1, const void *data2) = NULL;,只有当两个函数指针的参数个数,参数类型,返回值类型相同时才能够相互赋值(注:void类型可以认为跟任意类型相同),读取函数指针的内容(即调用指针指向的函数)(*match)(1, 3)或者match(1, 3),前一种是指针的语义形式而后一种则更为常用,其实函数指针取内容的语义跟普通指针略有不同,函数指针在取内容将会返回函数指针自己,并且C语言在语法上不允许函数指针的取内容语法出现在赋值语句左边,也就是说如果使用*match = value语法试图写入代码段则在编译阶段就会报错的

C语言中wrapper的实现

本文开始时提到,也许你打算给函数添加默认参数(C语言毕竟没有这个功能),或者你打算在函数调用之前/后做一些额外的处理,总之,当用户传入函数的功能与预期需求的功能有差异时,就需要wrapper用户传入的函数以返回具有预期功能的新函数,例如你现在基于已有代码进行二次开发,而你期望用户传入的函数与已有代码期望不同,这时你需要wrapper用户传入函数为已有代码期望的形式,见下面代码:

    /* 用户传入函数的占位符 */

    static void (*func)(const void *data) = NULL;

    /* wrapped函数 */

    static wrapped_func(const void *data){

       /* 前置处理 */ 

       func(data);  /* 有需要的话,这里进行参数类型的调整和默认值的设置 */

       /* 后置处理 */

    }

    void display(Graph *gp, void (*print)(const void *data)){

        func = print;  /* 更新用户函数占位符 */

        /* show函数是第三方代码 */

        show(Graph *gp, wrapped_func);  /* 将适配后的wrapped函数传入第三方代码 */

    }

wrapper实现的思路

  1. 定义全局函数指针变量,用以作为用户传入函数的占位符

  2. 定义wrapped函数,其中含有前置/后置处理逻辑,并调用了用户函数占位符

  3. 在调用第三方代码时,更新用户函数占位符并向第三方函数传入wrapped函数

Xiao Wenbin
Xiao Wenbin
Natural Language Processing Engineer

My research interests include machine learning, information retrieval and natural language processing.

Related