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;
}
|

浙公网安备 33010602011771号