Gobject的闭包

可以直接看红颜色的例子。

void  qsort (void*base,  size_t nmemb,  size_t size, int(*compar) (constvoid*, constvoid*));
闭包(Closure)的概念
    我们通过函数指针向 qsort 函数传入了一个函数 str_compare,这个函数被称为回调函数,但是它还有一个比较深奥的名字——“闭包”。
所谓闭包,简而言之,就是一个函数加上它所访问的所有非局部变量,而所谓“非局部变量”,表示这些变量对于那个函数而言既非局部变量,也非全局变量。
我们向 qsort 传入函数 str_compare,它所接受排序数据集合中的 2 个元素,而且 2 个元素对于 str_compare 而言,既非是全局变量,也非其局部变量,因此 str_compare 与这 2 个参数形成了一个闭包。
    在许多动态语言中,闭包通常也被昵称为“函数是第一类对象”,即函数与那些语言中基本类型具有相同的权利,例如函数可以存储在变量中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。
    在 C 语言中,利用函数指针并配合参数的复制与传递,可模拟闭包这种结构,但是在可读性上没有那些内建支持闭包的语言优雅。
GObject 提供了 GClosure 对象与方法,实现了功能比较全面的 C 闭包模拟,我们可以在程序中直接使用它。下面,通过一个很小的示例,演示 GClosure 的使用。
先来看一个非 GClosure 的 C 闭包示例:
#include <stdio.h>
#include <math.h>
#include <string.h>

  typedef_GCClosure GCClosure;
struct_GCClosure {
       GClosure    closure;
       gpointer    callback;
};
typedefint(*Func) (void*, void*);
 
staticvoid
compare (void*a, void*b, Func callback)
{
   int  r = callback (a, b);
   if(r == -1)
     printf("a < b\n");
    else if(r == 0)
       printf("a = b\n");
        else
        printf("a > b\n");
}
 
static int
float_compare (void*a, void*b)
{
        float*f1 = (float*)a;
        float*f2 = (float*)b;
 
        if(*f1 > *f2)
                return1;
        elseif(fabs(*f1 - *f2) <= 10E-6)
                return0;
        else
                return-1;
}
 
staticint
str_compare (void*a, void*b)
{
        size_tlen1 = strlen((char*)a);
        size_tlen2 = strlen((char*)b);
 
        if(len1 > len2)
                return1;
        elseif(len1 == len2)
                return0;
        else
                return-1;
}
 
int
main (void)
{       
        floata = 123.567;
        floatb = 222.222;
        Func func = float_compare;
        compare (&a, &b, func);
          
        char*s1 = "hello world!";
        char*s2 = "hello!";
        func = str_compare;
        compare (s1, s2, func);
          
        return0;
}
上述代码主要实现了一个 compare 函数,它可以比较两个任意类型数据的大小,前提是你要向它提供特定的回调函数(闭包),例如代码中的 float_compare 与 str_compare 函数,它们分别实现了浮点数比较与字符串比较。
将上述程序改为 GClosure 实现,如下:
#include <math.h>
#include <glib-object.h>
void
g_cclosure_user_marshal_INT__VOID_VOID (GClosure     *closure,
                                   GValue       *return_value G_GNUC_UNUSED,
                                   guint         n_param_values,
                                   constGValue *param_values,
                                   gpointer      invocation_hint G_GNUC_UNUSED,
                                   gpointer      marshal_data)
{
        typedefgint (*GMarshalFunc_INT__VOID_VOID) (gpointer     data1,
        gpointer     data2);
        registerGMarshalFunc_INT__VOID_VOID callback;
        registerGCClosure *cc = (GCClosure*) closure;
        registergpointer data1, data2;
        gint v_return;
          
        g_return_if_fail (return_value != NULL);
        g_return_if_fail (n_param_values == 1);
          
        if(G_CCLOSURE_SWAP_DATA (closure))
        {
          data1 = closure->data;
          data2 = g_value_peek_pointer (param_values + 0);
        }
        else
        {
           data1 = g_value_peek_pointer (param_values + 0);
                data2 = closure->data;
        }
        callback = (GMarshalFunc_INT__VOID_VOID) (
               marshal_data ? marshal_data : cc->callback);
        v_return = callback (data1, data2);
        g_value_set_int (return_value, v_return);
}
 
staticvoid
compare (GClosure *closure,void *b)
{
        GValue return_value = {0};
        GValue param_value  = {0};
        g_value_init (&return_value, G_TYPE_INT);
        g_value_init (&param_value, G_TYPE_POINTER);
          
        g_value_set_pointer (&param_value, b);
 
        g_closure_invoke (closure, &return_value, 1, &param_value, NULL);
        gint r = g_value_get_int (&return_value);
          
        if(r == -1)
                g_print ("a < b\n");
        elseif(r == 0)
                g_print ("a = b\n");
        else
                g_print ("a > b\n");
 
        g_value_unset (&return_value);
        g_value_unset (&param_value);
}
 
staticgint
float_compare (void*a, void*b)
{
        gfloat *f1 = a;
        gfloat *f2 = b;
          
        if(*f1 > *f2)
                return1;
        elseif(fabs(*f1 - *f2) <= 10E-6)
                return0;
        else
                return-1;
}
 
staticgint
str_compare (void*a, void*b)
{
        size_tlen1 = g_utf8_strlen ((gchar *)a, -1);
        size_tlen2 = g_utf8_strlen ((gchar *)b, -1);
 
        if(len1 > len2)
                return1;
        elseif(len1 == len2)
                return0;
        else
                return-1;
}
 
int
main (void)
{
        g_type_init ();
          
        gfloat a = 123.567;
        gfloat b = 222.222;
        GClosure *closure =
                g_cclosure_new (G_CALLBACK (float_compare), &a, NULL);
        g_closure_set_marshal (closure, g_cclosure_user_marshal_INT__VOID_VOID);
        compare (closure, &b);
        g_closure_unref (closure);
          
        gchar *s1 ="Hello World!\n";
        gchar *s2 ="Hello!\n";
        closure = g_cclosure_new (G_CALLBACK (str_compare), s1, NULL);
        g_closure_set_marshal (closure, g_cclosure_user_marshal_INT__VOID_VOID);
        compare (closure, s2);
        g_closure_unref (closure);
          
        return0;
}

下面这张图可以用来解释。

    GLib 库提供了一个名为 glib-genmarshal 的工具,它可以根据我们给出的函数描述信息产生有效的 marshal 代码。上文中的 g_cclosure_user_marshal_INT__VOID_VOID 函数,我便是使用这个工具产生的。

猜你喜欢

转载自blog.csdn.net/evsqiezi/article/details/82695585