author: hjjdebug
date: 2025年 06月 25日 星期三 15:35:26 CST
descrip: glib-object 中G_DEFINE_TYPE 宏都作了什么?
文章目录
- 1. 测试代码
- 2 给出它的展开式.
- 3.说说它都生成了什么?
- 3.1. my_foo_get_type() 函数
- 3.2. static GType my_foo_get_type_once(void)
- 3.3. my_foo_class_intern_init
- 3.4. my_foo_get_instance_private
- 4 小结:
讲多了也说不明白,就给一个简单的例子. 事实胜于雄辩
1. 测试代码
$ cat main.c
#include <glib-object.h>
// 用c 语言来完成类的继承
//假如想创建一个MyObject 类, 继承GObject 基类
//框架, 写两个类
struct _Foo {GObject obj1;int value;
};struct _FooClass {GObjectClass class1;
};
//定义两个小名
typedef struct _Foo Foo;
typedef struct _FooClass FooClass;//关键代码来了(一个复杂的宏),
//前面定义了2个类型Foo,FooClass,my_foo是名称前缀
G_DEFINE_TYPE(Foo, my_foo, G_TYPE_OBJECT)static void my_foo_init(Foo *self) {self->value = 0;
}
static void my_foo_class_init(FooClass *klass) {(void) klass;
}int main(void)
{return 0;
}
2 给出它的展开式.
本来我们一步一步把宏如何展开的给出来, 但是太复杂了. 直接给出G_DEFINE_TYPE展开的结果了.
其中G_TYPE_OBJECT 是一个整数 , 其值是 20<<2
$ cat readme.c
static void my_foo_init(Foo* self);
static void my_foo_class_init(FooClass* klass);
static GType my_foo_get_type_once(void);
static gpointer my_foo_parent_class = ((void*)0);static gint Foo_private_offset;
static void my_foo_class_intern_init(gpointer klass)
{my_foo_parent_class = g_type_class_peek_parent(klass);if (Foo_private_offset != 0)g_type_class_adjust_private_offset(klass, &Foo_private_offset);my_foo_class_init((FooClass*)klass);
} __attribute__((__unused__))static inline gpointer my_foo_get_instance_private(Foo* self)
{return (((gpointer)((guint8*)(self) + (glong)(Foo_private_offset))));
}
GType my_foo_get_type(void)
{static GType static_g_define_type_id = 0;if ((__extension__({ //断言static_g_define_type_id 就是 指针大小(64位机8字节)_Static_assert(sizeof *(&static_g_define_type_id) == sizeof(gpointer), "Expression evaluates to false");(void) (0 ? (gpointer) * (&static_g_define_type_id) : ((void *)0)); //这一行就是0(!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; //__typeof__是GNUC 扩展表达式__typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5); gapg_temp_newval; })) && g_once_init_enter_pointer (&static_g_define_type_id)); }))){GType g_define_type_id = my_foo_get_type_once();(__extension__({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id)); }));}return static_g_define_type_id;
} __attribute__((__noinline__))
static GType my_foo_get_type_once(void)
{GType g_define_type_id = g_type_register_static_simple(((GType)((20) << (2))), g_intern_static_string("Foo"), sizeof(FooClass), (GClassInitFunc)(void (*)(void))my_foo_class_intern_init, sizeof(Foo), (GInstanceInitFunc)(void (*)(void))my_foo_init, (GTypeFlags)0);{{{};}}return g_define_type_id;
}
3.说说它都生成了什么?
它生成了4个函数, my_foo_get_type,my_foo_get_type_once 用来获取类型id.
my_foo_class_intern_init, 类初始化
my_foo_get_instance_private 实例初始化
另外还定义了一个Foo_private_offset 变量
3.1. my_foo_get_type() 函数
extension 是是C语言中的一个编译器指令,
用于告诉编译器在宏定义中有一些语法扩展,可能不符合 ANSI 标准的语法,
不要动不动就被我警告或报错. 例如 __typeof__就是一种扩展语法
typeof (*(&static_g_define_type_id)) gapg_temp_newval;
__typeof__是GNUC 扩展表达式, 用以获取后边表达式的类型.
*(&static_g_define_type_id)通过取地址后解引用,本质上等价于直接访问static_g_define_type_id
该句就是定义一个变量gapg_temp_newval, 类型与static_g_define_type_id 一样
typeof ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id);
定义gapg_temp_atomic = &static_g_define_type_id;
__atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5);
向gapg_temp_newval 原子加载数值, 5代表内存模型,__ATOMIC_SEQ_CST(顺序一致性模型)
前边为真时,执行后边语句:g_once_init_enter_pointer (&static_g_define_type_id));
这是一个宏.
gboolean g_once_init_enter_pointer (void *location);
实际上就是取static_g_define_type_id 的值之意. 如果也为真,取反为假,则不执行大括号语句
但第一次static_g_define_type_id的值为0,取反后if条件为真,则执行大括号语句.
调用my_foo_get_type_once ,返回类型id->g_define_type_id,赋值给static_g_define_type_id
则以后再调该函数,因static_g_define_type_id 已经为真,不走if块语句,直接返回static_g_define_type_id
3.2. static GType my_foo_get_type_once(void)
向系统注册类. 返回定义的类型id g_define_type_id
注册函数原型:
GType g_type_register_static_simple (GType parent_type, //20<<2
const gchar *type_name, //Foo
guint class_size, // 类的大小,sizeof(FooClass)
GClassInitFunc class_init, // my_foo_class_intern_init
guint instance_size, // sizeof(Foo)
GInstanceInitFunc instance_init, // my_foo_init,
GTypeFlags flags); // 0
gpointer 就是void *, GType 就是uint64_t;
3.3. my_foo_class_intern_init
该函数会调用用户定义的my_foo_class_init
3.4. my_foo_get_instance_private
该函数很简单, 调整类指针指向私有地址
4 小结:
G_DEFINE_TYPE宏在GObject系统中自动生成了类型注册相关代码。
它会生成4个函数:
my_foo_get_type()用于获取类型ID,
my_foo_get_type_once()执行实际的类型注册,
my_foo_class_intern_init()处理类初始化,
my_foo_get_instance_private()管理实例私有数据。
关键是通过g_type_register_static_simple()注册新类型,指定父类型(G_TYPE_OBJECT)、
类大小、实例大小和初始化函数
该机制通过静态变量实现线程安全的单次初始化,为GLib的对象系统提供了类型注册的基础设施.
是c语言面向对象编程的实现。