glib-object 中G_DEFINE_TYPE 宏都作了什么?


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语言面向对象编程的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/web/86166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Alembic迁移系统初始化实战教程

下面是一份结构清晰、步骤明确的 基于 Alembic Pydantic SQLAlchemy 的数据库迁移系统初始化教程&#xff0c;非常适合初次搭建项目或团队规范流程参考。 &#x1f680; Alembic SQLAlchemy Pydantic 项目数据库迁移初始化教程 本教程将指导你如何从零初始化 Alembic 迁移…

灰度发布怎么保证数据库一致的

注&#xff1a; 以下内容来源于deepseek答案&#xff0c;生产环境以实际情况为主&#xff01; 在灰度发布中保证数据库一致的最优解需要同时满足安全性、低复杂度和高可操作性。结合多年实战经验&#xff0c;以下是最推荐的黄金方案&#xff08;适用于90%以上场景&#xff09;&…

不用vue,只用html,即可简单实现electron项目

为你提供一个 最简单的 Electron 项目模板&#xff0c;包含完整的代码、配置和打包说明。即使你是小白&#xff0c;也能快速上手。 1. 项目结构 /your-project├── main.js # Electron 主进程文件├── preload.js # 安全通信脚本&#xff08;可选&#xf…

C++11原子操作:从入门到精通

文章目录 一、什么是原子操作&#xff1f;二、为什么需要原子操作&#xff1f;三、C11中的<atomic>头文件四、基本使用1. 声明原子变量2. 基本原子操作 五、内存顺序&#xff08;Memory Order&#xff09;示例&#xff1a;使用内存顺序实现自旋锁 六、原子类型模板七、实…

深入解析Flink Local模式启动流程源码:揭开作业初始化的神秘面纱

在Flink的数据处理体系中&#xff0c;Local模式凭借无需依赖分布式集群资源的特性&#xff0c;成为开发测试阶段快速验证作业逻辑的利器。其启动流程的源码里&#xff0c;藏着从作业提交到任务执行的完整脉络。接下来&#xff0c;我们将深入关键代码段&#xff0c;逐行剖析Flin…

二刷 苍穹外卖 day06

HttpClient 用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包 作用&#xff1a; 发送HTTP请求 接受响应数据 应用场景&#xff1a; 当我们在使用扫描支付、查看地图、获取验证码、查看天气等功能时 其实&#xff0c;应用程序本身并未实现这些功能&#xff…

React第六十三节Router中BrowserRouter的用途及注意事项

前言 BrowserRouter 是 React Router 库的核心组件&#xff0c;用于实现单页面应用&#xff08;SPA&#xff09;的客户端路由。它利用 HTML5 History API 管理 URL&#xff0c;实现页面无刷新跳转。下面详细解释其用途、使用方法和代码示例&#xff1a; 一、BrowserRouter 核…

《Self-Adapting Language Models》(SEAL)代码阅读笔记

代码&#xff1a;https://github.com/Continual-Intelligence 脚本命令用法&#xff1a;knowledge-incorporation/README.md 生成self-edit数据 脚本&#xff1a;sbatch knowledge-incorporation/scripts/make_squad_data.sh vllm serve启动Qwen2.5-7B模型的服务。 执行self-e…

GelSight Mini视触觉传感器开发资源升级:触觉3D点云+ROS2助力机器人科研与医疗等应用

近日&#xff0c;GelSight宣布对其GelSight Mini视触觉传感器的GitHub支持页面进行重大更新&#xff0c;围绕3D点云重建、ROS2 集成及开发者支持体系推出三大核心升级&#xff0c;助力机器人触觉感知、工业检测及科研场景落地。 GelSight Mini视触觉传感器重磅发布&#xff01;…

6、做中学 | 三年级下期 Golang值类型相互转换

本次为操作文章&#xff0c;大部分都在讨论类型之间如何转换&#xff0c;使用的是内置方法进行调用执行&#xff0c;详细使用请移步至&#xff1a; go的API使用文档地址 https://studygolang.com/pkgdoc 一、数值类型相互转换 go中数值转换需要显示转换&#xff0c;不能隐式自…

019 高校心理教育辅导系统技术解析:构建心理健康守护平台

高校心理教育辅导系统技术解析&#xff1a;构建心理健康守护平台 在关注大学生心理健康成为教育重点的当下&#xff0c;高校心理教育辅导系统借助数字化技术整合多种功能模块&#xff0c;面向管理员、学生、教师三类角色&#xff0c;实现心理教育辅导工作的高效化与精准化。本…

【ArcGIS】土地资源单项评价

【ArcGIS】土地资源单项评价 一、土地资源单项评价1、评价思路 二、操作步骤1、处理环境设置2、地形坡度评价3、高程评价4、坡度高程叠加评价5、地形起伏度6、土地资源综合评价 一、土地资源单项评价 1、评价思路 &#xff08;1&#xff09;利用全域DEM计算地形坡度&#xff…

Prioritized Generative Replay

ICLR 2025 Oral code 具有样本效率的 online reinforcement learning (RL) 通常使用 replay buffer 存储经验&#xff0c;以便在更新价值函数时重复使用。然而&#xff0c;uniform replay 效率低下&#xff0c;因为某些类型的 transition 可能与学习更相关。 虽然对更有用的样本…

Linux -- 线程、锁

1、 Linux线程概念 1.1、什么是线程 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程线程在进程内部运行&#xff0c;本质是在进程地址空间内运行在Linux系统中…

海外服务器的定义和作用都有哪些?

海外服务器可以说是一个统称&#xff0c;其中包含了全球各地除了中国大陆以外其他国家的服务器&#xff0c;在如今的数字化时代中&#xff0c;海外服务器的应用已经成为跨国企业业务拓展、科研与学术交流等多个领域中不可或缺的一部分&#xff0c;能够为各个行业提供更加稳定且…

数据结构之优先级队列

系列文章目录 数据结构之ArrayList_arraylist o(1) o(n)-CSDN博客 数据结构之LinkedList-CSDN博客 数据结构之栈-CSDN博客 数据结构之队列-CSDN博客 数据结构之二叉树-CSDN博客 目录 系列文章目录 前言 一、优先级队列和堆 二、堆的模拟实现 1. 堆的创建 2. 计算建堆…

【版本控制教程】如何使用Unreal Engine 5 + UE源代码控制(Perforce P4)

本文来源perforce.com&#xff0c;由Perforce中国授权合作伙伴——龙智翻译整理&#xff0c;旨在为国内用户提供一份实用、易懂的Unreal Engine 5Perforce P4的中文使用指南。希望能为UE开发者、设计师和美术小伙伴们的版本控制实践提供有力支持~ Unreal Engine 5 是一款尖端的…

opensingleComDialog方法解析优化

下面是对 opensingleComDialog 方法的详细解析&#xff0c;并给出优化建议和优化后的代码。 方法解析 作用 opensingleComDialog(index) 方法用于在输入框失去焦点时&#xff08;blur 事件&#xff09;自动根据输入内容进行唯一性查询&#xff0c;如果查到唯一结果则自动填充…

css 实现1个像素在不同分辨率屏幕上画网格线

实现网格线绘制&#xff0c;要考虑画布style尺寸和画布像素大小的缩放关系 单像素绘制主要出现的问题是会模糊&#xff0c;从像素角度看就是出现绘制两个像素&#xff0c;实际就是要做偏移 核心就是&#xff1a;按物理像素绘制&#xff0c;首先要对齐物理像素&#xff0c;计算…

深度图聚类DGC—Paper Notes

目录 Unsupervised Deep Embedding for Clustering Analysis (DEC 2016)Attributed Graph Clustering: A Deep Attentional Embedding Approach (DAEGC 2019)Structural Deep Clustering Network (SDCN 2020)Contrastive Multi-View Representation Learning on Graphs (MVG…