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.pswp.cn/web/86166.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/86166.shtml
英文地址,請注明出處:http://en.pswp.cn/web/86166.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋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…