c语言exe外包装,使用Boxed Type机制包装C语言结构体

注:之前曾写过一篇类似文章,结果被我误删了

25a2a136bc372440058acaa1fdb5a2f6.gif

按照GObject手册的说法,Boxed Type机制是用来包装(wrap)C语言结构体的一种机制。这里所谓的包装,其实就是在GType类型系统中注册该类型,并且该类型将成为GBoxed的子类。之后,这一类型就能够使用和GBoxed类型有关的所有函数了,如g_value_get_boxed等等。

首先,我们看一下GBoxed在GType类型系统中的“注册信息”:

void

g_boxed_type_init (void)

{

static const GTypeInfo info = {

0, /* class_size */

NULL, /* base_init */

NULL, /* base_destroy */

NULL, /* class_init */

NULL, /* class_destroy */

NULL, /* class_data */

0, /* instance_size */

0, /* n_preallocs */

NULL, /* instance_init */

NULL, /* value_table */

};

const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };

GType type;

/* G_TYPE_BOXED

*/

type = g_type_register_fundamental (G_TYPE_BOXED, g_intern_static_string ("GBoxed"), &info, &finfo,

G_TYPE_FLAG_ABSTRACT | G_TYPE_FLAG_VALUE_ABSTRACT);

g_assert (type == G_TYPE_BOXED);

}

从以上信息中,我们可以看出,GBoxed是一个基本类型,不可实例化(instantiable)、不可类化(classed),可以被继承,但不可以被深继承(即继承了GBoxed的子类不能再被继承)。

要想在GType类型系统中注册一个Boxed Type,我们需要提供一个copy_func和一个free_func,从名字上也可以看出,前者负责该类型的拷贝,后者负责该类型的释放。

为更方便地说明问题,我们假设我们需要包装以下的StudentInfo类型:

typedef struct _StudentInfo StudentInfo;

struct _StudentInfo

{

gint number;

GString *name;

gdouble grade;

};

为了包装该类型,我们自然需要提供一个copy_func和一个free_func:

StudentInfo *student_info_new(gint number,gchar *name,gdouble grade)

{

StudentInfo *new_std;

new_std=g_new(StudentInfo,1);

new_std->number=number;

new_std->name=g_string_new(name);

new_std->grade=grade;

return new_std;

}

StudentInfo *student_info_copy(const StudentInfo *std_info)

{

StudentInfo *new_std;

new_std=g_new(StudentInfo,1);

new_std->number=std_info->number;

new_std->name=g_string_new(std_info->name->str);

new_std->grade=std_info->grade;

return new_std;

}

下面,我们需要一个student_info_type_init函数来承担运行时刻注册该类型的任务。为方便起见,我们也为该函数配套了一个宏:

GType student_info_get_type()

{

static GType student_info_id=0;

if (student_info_id==0)

{

student_info_id=g_boxed_type_register_static("StudentInfo",(GBoxedCopyFunc)student_info_copy,(GBoxedFreeFunc)student_info_free);

}

return student_info_id;

}

#define TYPE_STUDENT_INFO (student_info_get_type())

从上面的代码中可以看出,Boxed Type的注册工作实质上是由g_boxed_type_register_static函数完成的,该函数原型如下:

GType g_boxed_type_register_static (const gchar *name,

GBoxedCopyFunc boxed_copy,

GBoxedFreeFunc boxed_free);

该函数有三个参数,其中name是Boxed Type的名字,GBoxedCopyFunc和GBoxedFreeFunc则是用typedef定义的函数指针类型:

typedef gpointer (*GBoxedCopyFunc) (gpointer boxed);

typedef void (*GBoxedFreeFunc) (gpointer boxed);

至此,包装工作就完成了。

但是上面给出的student_info_get_type()函数有一个问题:它不是线程安全的。而且,每次写这么多也显得很臃肿,为此,我们可以使用一个宏G_DEFINE_BOXED_TYPE:

#define G_DEFINE_BOXED_TYPE(TypeName, type_name, copy_func, free_func) G_DEFINE_BOXED_TYPE_WITH_CODE (TypeName, type_name, copy_func, free_func, {})

该宏有4个参数:

TypeName: 该参数是该Boxed Type的名字,且不用引号包围。

type_name: 该参数将成为_get_type()的前缀,即最终自动生成的函数的名字为type_name_get_type()

copy_func: 该参数为函数指针或函数名(函数指针常量?),其类型应为以下三种之一:

typedef gpointer (*copy_func) (gpointer boxed);

typedef TypeName *(*copy_func) (const TypeName *boxed);

typedef TypeName *(*copy_func) (TypeName *boxed);

free_func: 该参数为函数指针或函数名(函数指针常量?),其类型应为以下两种之一:

typedef void (*free_func) (gpointer boxed);

typedef void (*free_func) (TypeName *boxed);

因此,如果想生成student_info_get_type()函数的话,只要按如下所示填写参数:

G_DEFINE_BOXED_TYPE(StudentInfo,student_info,student_info_copy,student_info_free);

如果你由于种种原因而需要自己写*_get_type()函数的话,为使其线程安全,可以将以下代码作为模板使用:

GType

g_strv_get_type (void)

{

static volatile gsize g_define_type_id__volatile = 0;

if (g_once_init_enter (&g_define_type_id__volatile))

{

GType g_define_type_id =

g_boxed_type_register_static (g_intern_static_string ("GStrv"),

(GBoxedCopyFunc) g_strdupv,

(GBoxedFreeFunc) g_strfreev);

g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);

}

return g_define_type_id__volatile;

}

事实上,很久以前,G_DEFINE_BOXED_TYPE展开以后,也是和上面的代码类似的——之所以要改用现在的写法,主要还是为了增强对类型的检测。

完整的测试代码如下:

#include

#include

#include

typedef struct _StudentInfo StudentInfo;

struct _StudentInfo

{

gint number;

GString *name;

gdouble grade;

};

StudentInfo *student_info_new(gint number,gchar *name,gdouble grade)

{

StudentInfo *new_std;

new_std=g_new(StudentInfo,1);

new_std->number=number;

new_std->name=g_string_new(name);

new_std->grade=grade;

return new_std;

}

void student_info_print(const StudentInfo *std_info)

{

g_print("Number:%3d Name:%5s Grade:%3.1f",std_info->number,std_info->name->str,std_info->grade);

}

StudentInfo *student_info_copy(const StudentInfo *std_info)

{

StudentInfo *new_std;

new_std=g_new(StudentInfo,1);

new_std->number=std_info->number;

new_std->name=g_string_new(std_info->name->str);

new_std->grade=std_info->grade;

return new_std;

}

void student_info_free(StudentInfo *std_info)

{

g_string_free(std_info->name,TRUE);

g_free(std_info);

}

G_DEFINE_BOXED_TYPE(StudentInfo,student_info,student_info_copy,student_info_free);

#define TYPE_STUDENT_INFO (student_info_get_type())

int main()

{

StudentInfo *stdi;

StudentInfo *stdi_copy;

g_type_init();

stdi=student_info_new(1,"JIm",86.5);

stdi_copy=g_boxed_copy(TYPE_STUDENT_INFO,stdi);

student_info_print(stdi_copy);

g_boxed_free(TYPE_STUDENT_INFO,stdi);

g_boxed_free(TYPE_STUDENT_INFO,stdi_copy);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值