GObject[7] 闭包-GClosure

一、回调函数

首先得知道回调函数的知识,C语言回调函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
static int
str_compare (const void *s1, const void *s2)
{
        char *str1 = *(char **)s1;
        char *str2 = *(char **)s2;       
        size_t l1 = strlen (str1);
        size_t l2 = strlen (str2);
 
        if (l1 > l2)
                return 1;
        else if (l1 == l2)
                return 0;
        else
                return -1;
}
 
int
main (void)
{
        char *str_array[5] = {"a", "abcd", "abc", "ab", "abcde"};
        qsort (str_array, 5, sizeof (char *), str_compare);
 
        for (int i = 0; i< 5; i++)
                printf ("%s ", str_array[i]);
        printf ("\n");
         
        return 0;
}

二、闭包

        在上述中的str_compare函数被称为回调函数,这个回调函数加上他的两个参数就形成了一个闭包。

三、GClosure:GClosure是GObject 提供的对象与方法,实现了功能比较全面的 C 闭包模拟,我们可以在程序中直接使用它。

1、GClosure 包含两个结构体

首先是GClosure结构体

struct GClosure{
    gpointer data指针;
    marshal函数指针;
    gpointer marshal_data指针;
};

然后是GCClosure结构体

typedef _GCClosure GCClosure;
struct _GCClosure {
        GClosure    closure; //继承了GClosure结构体
        gpointer    callback; //gpointer是void*的别名,所以callback就是一个无类型指针
};

它们之间的数据结构体如下:图片来自http://garfileo.is-programmer.com/2011/3/20/function-pointer-and-callback-function-and-closure.25453.html

以下就是新建了一个闭包

GClosure *closure = g_cclosure_new (G_CALLBACK (float_compare), &a, NULL);
g_closure_set_marshal (closure, g_cclosure_user_marshal_INT__VOID_VOID);

所以就很清楚:

callback指针指向了回调函数。

data指针指向的是要传给回调函数的第一个参数。

marshal指针指向了g_cclosure_user_marshal_*函数,这个又臭又长的恶心函数应该是通用的,可以用命令产生里面的代码。

marshal_data指针是指向回调函数的,但是已经有callback指针指向回调函数了呀,其实marshal_data可以看作是一个开关,它可以暂时屏蔽 GCClosure 中的 callback 所指向的回调函数,而启用 marshal_data 所指向的回调函数。。

可以通过 g_closure_set_meta_marshal 函数设置了 closure 闭包的 marshal_data 指针,此时指向了marshal_data 指针 str_compare_new 函数,而callback的值会是marshal_data 。

 g_closure_set_meta_marshal (closure, str_compare_new, 
                                    g_cclosure_user_marshal_INT__VOID_VOID);

闭包调用的这个过程如下:

g_closure_invoke函数是库里面有的,不用自己定义。

上图也就是:把闭包和回调函数的其他参数传入到compare函数里,在compare函数里调用g_closure_invoke函数,g_closure_invoke函数需要的参数有闭包和包含回调函数其他参数的容器,g_closure_invoke会调用那个恶心的函数,那个恶心的函数调用回到函数,具体传入什么参数,返回什么值上图都很清楚。

完整代码,

#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,
                                        const GValue *param_values,
                                        gpointer      invocation_hint G_GNUC_UNUSED,
                                        gpointer      marshal_data)
{
        typedef gint (*GMarshalFunc_INT__VOID_VOID) (gpointer     data1,
                                                     gpointer     data2);
        register GMarshalFunc_INT__VOID_VOID callback;
        register GCClosure *cc = (GCClosure*) closure;
        register gpointer 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);
}
 
static void
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");
        else if (r == 0)
                g_print ("a = b\n");
        else
                g_print ("a > b\n");
 
        g_value_unset (&return_value);
        g_value_unset (&param_value);
}
 
 
static gint
str_compare (void *a, void *b)
{
        size_t len1 = g_utf8_strlen ((gchar *)a, -1);
        size_t len2 = g_utf8_strlen ((gchar *)b, -1);
 
        if (len1 > len2)
                return 1;
        else if (len1 == len2)
                return 0;
        else
                return -1;
}
 
static gint
str_compare_new (void *a, void *b)
{
        g_print ("\nI'm a new marshaller\n");
 
        return (str_compare (a, b));
}
 
int
main (void)
{
        g_type_init ();
         
        gchar *s1 = "Hello World!\n";
        gchar *s2 = "Hello!\n";
 
        GClosure *closure = g_cclosure_new (G_CALLBACK (str_compare), s1, NULL);
        //第一次调用的compare的时候,回调函数是str_compare,callback指向它
        g_closure_set_marshal (closure, g_cclosure_user_marshal_INT__VOID_VOID);
        compare (closure, s2);
         
        //第二次调用的时候,以下函数更改了marshal_data指向的回调函数为str_compare_new
        g_closure_set_meta_marshal (closure, str_compare_new, 
                                    g_cclosure_user_marshal_INT__VOID_VOID);
        compare (closure, s2);  
 
        g_closure_unref (closure);
         
        return 0;
}

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值