GValue

在C语言里,通用类型我们一般是用void *以表示任何类型的数据。但GObject的设计初衷是为了解决多语言交互问题,所以必须设计出一套能容纳任何数据类型的通用数据类型。以便在不同的编程语言之间进行数据转换操作。这个数据类型就是GValue。

struct _GValue
{
 


  GType        g_type;

 
  union {
    gint    v_int;
    guint    v_uint;
    glong    v_long;
    gulong    v_ulong;
    gint64      v_int64;
    guint64     v_uint64;
    gfloat    v_float;
    gdouble    v_double;
    gpointer    v_pointer;
  } data[2];
};

它包括两个字段,一个是g_type这个用来表示GValue里保存的是哪种类型的数据。另外一个就是用来保存真正数据的data[2]。为什么用 data[2],而不是直接一个data呢?还没搞清楚。看注释,反正这些数据结构都是“私有”的,而且不能做任何假设。所以先不管它了。

GValue几个有用的宏:
1)G_TYPE_IS_VALUE(type) : 判断type能否用GValue来表达。是否可以用g_value_init来初始化一个类型为type的GValue。这是因为GObject的数据类型是动态注册的。在用g_value_init初始化前,必须判断这个类型是否已经注册。
2)G_IS_VALUE(value) :判断value是否已经初始化。即value->g_type已经被初始化为一种特定的数据类型了。看代码和G_TYPE_IS_VALUE一 样,都是判断type_check_is_value_type_U来判断。不同的是G_TYPE_IS_VALUE这个宏用宏参数来调用,而 G_IS_VALUE则用value->g_type来调用。
3)G_VALUE_TYPE(value) :判断value的类型。外面只能用这个宏来访问g_type成员。
4)G_VALUE_TYPE_NAME(value) :类型的名称。在GObject动态类型系统里,每种类型都有一个ASCII表示的名称。如"gchar","gint"等等。
5)G_VALUE_HOLDS(value,type):判断value是否表示type类型的数据

GValue赋值:

GValue*
g_value_init (GValue *value, GType   g_type);
把value初始化为g_type类型的数据。


void
g_value_copy (const GValue *src_value, GValue *dest_value);
值的拷贝。

g_value_set_XXX用来设置已经初始化好的GValue,g_value_get_XXX用来读取GValue里的值:
void              g_value_set_char        (GValue          *value,
                         gchar           v_char);
gchar              g_value_get_char        (const GValue *value);
void              g_value_set_uchar        (GValue          *value,
                         guchar           v_uchar);
guchar              g_value_get_uchar        (const GValue *value);
void              g_value_set_boolean    (GValue          *value,
                         gboolean      v_boolean);
gboolean          g_value_get_boolean    (const GValue *value);
void              g_value_set_int        (GValue          *value,
                         gint           v_int);
gint              g_value_get_int        (const GValue *value);
void              g_value_set_uint        (GValue          *value,
                         guint           v_uint);
guint              g_value_get_uint        (const GValue *value);
void              g_value_set_long        (GValue          *value,
                         glong           v_long);
glong              g_value_get_long        (const GValue *value);
void              g_value_set_ulong        (GValue          *value,
                         gulong           v_ulong);
gulong              g_value_get_ulong        (const GValue *value);
void              g_value_set_int64        (GValue          *value,
                         gint64           v_int64);
gint64              g_value_get_int64        (const GValue *value);
void              g_value_set_uint64    (GValue          *value,
                         guint64      v_uint64);
guint64              g_value_get_uint64    (const GValue *value);
void              g_value_set_float        (GValue          *value,
                         gfloat           v_float);
gfloat              g_value_get_float        (const GValue *value);
void              g_value_set_double    (GValue          *value,
                         gdouble       v_double);
gdouble              g_value_get_double    (const GValue *value);
void              g_value_set_string    (GValue          *value,
                         const gchar  *v_string);
void              g_value_set_static_string (GValue          *value,
                         const gchar  *v_string);
G_CONST_RETURN gchar* g_value_get_string    (const GValue *value);
gchar*              g_value_dup_string    (const GValue *value);
void              g_value_set_pointer    (GValue          *value,
                         gpointer      v_pointer);
gpointer          g_value_get_pointer    (const GValue *value);
GType              g_gtype_get_type        (void);
void              g_value_set_gtype            (GValue          *value,
                         GType         v_gtype);
GType                  g_value_get_gtype            (const GValue *value);

实现机制:
其实,GValue只是一个接口。给GValue的使用者提供一个统一的界面。其实现留给了具体的数据类型。因为只有具体的数据类型才知道怎样处理这种类 型的数据。举个例子,调用g_value_copy进行值的拷贝时,只有特定的数据类型才知道保存在GValue里的数据需要如何来实现拷贝。所以,在向 GObject动态类型中注册数据类型时(生成一种新的GType),需要提供一个GTypueTable:
struct _GTypueTable
{
  void     (*value_init)         (GValue       *value);
  void     (*value_free)         (GValue       *value);
  void     (*value_copy)         (const GValue *src_value,
                  GValue       *dest_value);
 
  gpointer (*value_peek_pointer) (const GValue *value);
  gchar        *collect_format;
  gchar*   (*collect_value)      (GValue       *value,
                  guint         n_collect_values,
                  GTypeCValue  *collect_values,
                  guint        collect_flags);
  gchar        *lcopy_format;
  gchar*   (*lcopy_value)        (const GValue *value,
                  guint         n_collect_values,
                  GTypeCValue  *collect_values,
                  guint        collect_flags);
};
即提供一个处理这种类型的数据的接口。而注册一种新的数据类型需要提供GTypeInfo的数据结构:
struct _GTypeInfo
{
 
  guint16                class_size;
 
  GBaseInitFunc          base_init;
  GBaseFinalizeFunc      base_finalize;
 
 
  GClassInitFunc         class_init;
  GClassFinalizeFunc     class_finalize;
  gconstpointer          class_data;
 
 
  guint16                instance_size;
  guint16                n_preallocs;
  GInstanceInitFunc      instance_init;
 
 
  const GTypueTable    *value_table;
};
其中最后一项value_table就是用来处理具体的数据类型的接口。

当然,并不是每注册一个数据类型都必须提供一个value_table,这是因为GObject系统已经提供了基础类型(Fundamental Type)的值的处理接口的实现。而且从GObject继承时,默认继承GObject类的value_table。

示例代码:
static void test_int (void)
{
  GValue a_value = {0, };
  GValue b_value = {0, };
  guint64 a, b;

  a = 0xdeadbeaf;

  g_value_init (&a_value, G_TYPE_UINT64);
  g_value_set_uint64 (&a_value, a);

  g_value_init (&b_value, G_TYPE_UINT64);
  g_value_copy (&a_value, &b_value);

  b = g_value_get_uint64 (&b_value);

  if (a == b) {
    g_print ("Yay !! 10 lines of code to copy around a uint64.\n");
  } else {
    g_print ("Are you sure this is not a Z80 ?\n");
  }
}

static void test_object (void)
{
  GObject *obj;
  GValue obj_vala = {0, };
  GValue obj_valb = {0, };
  obj = g_object_new (MAMAN_TYPE_BAR, NULL);

  g_value_init (&obj_vala, MAMAN_TYPE_BAR);
  g_value_set_object (&obj_vala, obj);

  g_value_init (&obj_valb, G_TYPE_OBJECT);

 
  g_value_copy (&obj_vala, &obj_valb);

  g_object_unref (G_OBJECT (obj));
  g_object_unref (G_OBJECT (obj));
}
 
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/* 
   Compile:
      gcc -g -Wall `pkg-config --cflags --libs glib-2.0 gobject-2.0`  \
         gvalue.c -o gvalue 
*/

#include <glib.h>
#include <glib/gprintf.h>
#include <glib-object.h>
#include <stdlib.h>

static void
string2int (const GValue *src_value,
            GValue       *dest_value)
{
    const gchar *value = g_value_get_string (src_value);
    int i = atoi(value);
    g_value_set_int (dest_value, i);
}

int
main (int   argc,
      char *argv[])
{
    /* GValues must start zero-filled */
    GValue a = {0};
    GValue b = {0};

    g_type_init ();

    /* The GValue starts empty */
    g_assert (!G_VALUE_HOLDS_STRING (&a));
    
    /* Put a string in it */
    g_value_init (&a, G_TYPE_STRING);
    g_assert (G_VALUE_HOLDS_STRING (&a));
    g_value_set_static_string (&a, "Hello, world!");
    g_printf ("%s\n", g_value_get_string (&a));

    /* Reset it to its pristine state */
    g_value_unset (&a);
    
    /* It can then be reused for another type */
    g_value_init (&a, G_TYPE_INT);
    g_value_set_int (&a, 42);

    /* Attempt to transform it into a GValue of type STRING */
    g_value_init (&b, G_TYPE_STRING);
    
    /* An INT is transformable to a STRING */
    g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING));
    
    g_value_transform (&a, &b);
    g_printf ("%s\n", g_value_get_string (&b));


    /* An STRINT is not transformable to INT */
    if (g_value_type_transformable (G_TYPE_STRING, G_TYPE_INT)) {
        g_printf ("Can transform string to int\n");
    } else
        g_printf ("Can Not transform string to int\n");
    
    /* Attempt to transform it again using a custom transform function */
    g_value_set_string(&b, "43");
    g_value_register_transform_func (G_TYPE_STRING, G_TYPE_INT, string2int);
    g_value_transform (&b, &a);
    g_printf ("%d\n", g_value_get_int(&a));

    return 0;
}
posted @ 2011-12-14 15:04  alxe_yu  阅读(2751)  评论(0)    收藏  举报