七、GObject闭包

  闭包:一个函数加上它所访问的所有非局部变量(传入的参数?)

#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
float_compare (void *a, void *b)
{
  gfloat *f1 = a;
  gfloat *f2 = b;
    
  if (*f1 > *f2)
          return 1;
  else if (fabs (*f1 - *f2) <= 10E-6)
          return 0;
  else
          return -1;
}
 
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;
}
 
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);
    
  return 0;
}

分析
g_cclosure_new函数创建了一个面向C语言的闭包。之所以在此强调是面向C语言的,那是因为GObject的闭包是面向任意语言的,例如pyg_closure_new函数可以创建python语言的闭包。返回值是一个GCClosure结构体。注意区别GCClosure和GClosure

typedef struct _GClosure  GClosure;
struct _GCClosure
{
  GClosure	closure; /*GObject提供的闭包结构*/
  gpointer	callback;/*指向回调函数的指针*/
};
/* GClosure结构体主要是面向各种语言对闭包的公有功能进行了基本抽象,这样所有要与GObject闭包机制打交道的语言,可以先继承GClosure结构体,然后根据自身需要再添加一些特点的数据成员。例如GCClosure就添加了callback无类型数据指针,用于指向闭包所对应的回调函数 */
struct _GClosure
{
  /*< private >*/
  volatile      	guint	 ref_count : 15;
  /* meta_marshal is not used anymore but must be zero for historical reasons
     as it was exposed in the G_CLOSURE_N_NOTIFIERS macro */
  volatile       	guint	 meta_marshal_nouse : 1;
  volatile       	guint	 n_guards : 1;
  volatile       	guint	 n_fnotifiers : 2;	/* finalization notifiers */
  volatile       	guint	 n_inotifiers : 8;	/* invalidation notifiers */
  volatile       	guint	 in_inotify : 1;
  volatile       	guint	 floating : 1;
  /*< protected >*/
  volatile         	guint	 derivative_flag : 1;
  /*< public >*/
  volatile       	guint	 in_marshal : 1;
  volatile       	guint	 is_invalid : 1;

  /*< private >*/	void   (*marshal)  (GClosure       *closure,
					    GValue /*out*/ *return_value,
					    guint           n_param_values,
					    const GValue   *param_values,
					    gpointer        invocation_hint,
					    gpointer	    marshal_data);
  /*< protected >*/	gpointer data;

  /*< private >*/	GClosureNotifyData *notifiers;
};
GClosure *closure = g_cclosure_new (G_CALLBACK (float_compare), &a, NULL);
g_closure_set_marshal (closure, g_cclosure_user_marshal_INT__VOID_VOID);

  以上两行代码实现了下图所示的数据结构。GClosure主要了解三个成员是marshal、data与marshal_data。其中marshal是一个函数指针,指向一个回调函数的调用者;data与marshal_data皆为gpointer指针类型。对于C语言闭包,data是向回调函数传输数据的地址,而marshal_data则指向回调函数。
  callback指针和marshal_data指针都指向回调函数。因为GObject库允许你自由切换回调函数,可将marshal_data看作是一个开关,它可以暂时屏蔽GCClosure中的callback所指向的回调函数,而启用marshal_data所指向的回调函数。
在这里插入图片描述
  compare函数运行流程如图
  我的理解g_cclosure_user_marshal_INT__VOID_VOID 函数就是判断运行callback指向的回调还是marshal_data指向回调函数。最终的浮点a、b和float_compare都会在g_cclosure_user_marshal_INT__VOID_VOID函数中出现。
在这里插入图片描述
*如何生成g_cclosure_user_marshal_函数?
GLib 库提供了一个名为 glib-genmarshal 的工具,它可以根据我们给出的函数描述信息产生有效的 marshal 代码。上文中的 g_cclosure_user_marshal_INT__VOID_VOID 函数,我便是使用这个工具产生的。
首先,准备好一份文本文档,例如 in__void_void.txt:

INT:VOID,VOID

然后,执行命令:

$ glib-genmarshal --body int__void_void.txt > int__void_void.c

即可产生 g_cclosure_user_marshal_INT__VOID_VOID 函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值