免费网站后台管理系统html,设计机构,网站建设链接,坡头网站建设公司GNOME编程基础与GLib库入门1. 编程基础要求在开始相关编程之前#xff0c;你需要具备一定的编程经验#xff1a;- 扎实的C语言编程经验#xff0c;包括指针、动态分配的数据结构和函数指针的使用#xff0c;同时要熟悉枚举类型和位域。- 熟练掌握指针的指针#xff08;** …GNOME编程基础与GLib库入门1. 编程基础要求在开始相关编程之前你需要具备一定的编程经验- 扎实的C语言编程经验包括指针、动态分配的数据结构和函数指针的使用同时要熟悉枚举类型和位域。- 熟练掌握指针的指针** 类型了解其使用场景以及如何提取和使用指针的地址。- 理解C宏和C预处理器。- 对Unix有基本的了解包括进程、库、搜索路径等。- 具备实际的Unix使用经验如使用文本编辑器、编写shell脚本和使用make工具。- 作为用户对GNOME有基本的了解知道GNOME 2.0应用程序的外观和操作方式以及如何与图形用户元素如控制面板和对话框进行交互。- 对GUI编程有一定的了解会有帮助了解回调函数事件处理程序的概念和工作原理会很有好处但这不是必需的。不过你不需要具备以下方面的经验- GTK 或 GNOME 编程经验。- C 语言以外的编程语言经验。- 面向对象编程经验。- 模型 - 视图 - 控制器MVC编程经验。2. 内容限制相关资料的内容介于教程和参考手册之间为避免内容过于臃肿有以下限制- 不包含完整的API参考特别是很少使用或已过时的函数和类。- 省略某些实现细节如纯内部的数据结构、库和函数或仅与GNOME库进一步开发相关的内容。- 为了给最常用的类和函数留出更多空间包含一些不常用API组件的参考资料但没有示例。- 不会详细介绍如何从一个想法实现一个完整、健壮、优雅的GUI应用程序其目标不是软件工程编程示例主要用于演示类和函数而非完整的应用程序。3. 排版约定排版风格与其他编程书籍类似- 文件、库、GConf键和URL使用斜体如 gobject.h, /apps/gconfdemo/ pictures_as_words, 和 http://www.gnome.org/ 。- 术语首次出现时使用粗斜体。- 菜单命令使用粗体用大于号分隔例如 File Open 或 Help Info。- C代码、shell命令、函数名和变量名使用等宽字体如GtkWidget *foo gtk_widget_new();可通过函数名后的括号区分函数。- 类名使用粗体如GtkWidget。- 对象名使用等宽字体常看到 “a GConfClient object” 来指代类的不确定对象。- 参数使用等宽斜体如G_OBJECT(object)中的object。- 属性和信号使用等宽粗体如changed,set−size, 和shadow−type。- 伪代码用两组尖括号括起来使用等宽字体如 save humanity 常看到 ... 表示其功能要么明显要么未定义。- 文献引用使用方括号如 [Wirth] 和 [Pennington] 。4. 平台GTK 和 GNOME 逐渐变得平台无关但主要的工作环境是Unix。当Unix系统之间存在差异时更倾向于使用具有Linux内核的GNU系统即GNU/Linux或简称为Linux。一般会尽量避免操作系统依赖但为了节省空间和提高清晰度更倾向于GNU平台因为绝大多数GNOME安装在该平台上。5. 编程示例编程示例非常重要至少应该浏览一下了解它们的功能和基本工作原理。很多示例不是完整有效的C程序前几章主要是简短的多行代码片段用于演示周围文本中描述的函数调用。完整的程序可以在 http://www.nostarch.com/gnome.htm 获取。如果遇到未声明的变量可查看前面的页面找到其声明。当预处理指令如#include出现在函数调用之前需要在源代码开头的某个位置使用该指令。6. 函数和宏要记住只能调用函数。宏的应用看起来很像函数调用但它是在编译器将源代码转换为目标代码之前进行的展开。在大多数API中很难区分哪些是函数哪些是宏因此不做严格区分。7. 计数规则在C语言中数组和字段的索引从0开始。为避免错误在其他领域也遵循此约定特别是在列表中例如GLib的列表元素索引。8. 路径名规则路径名系统遵循automake规则$(prefix)指的是GNOME安装的前缀例如/usr 或 /opt/gnome2。9. 指针和地址GTK 和 GNOME 广泛使用指针的指针有时将指针的指针称为指针的地址通常使用ptr这样的参数其中ptr是一个指针。10. GLib库介绍10.1 简介字母G在开源软件领域无处不在它代表GNURichard Stallman的 “GNU’s Not Unix” 。在很多名称中都会看到它如GTK, GLib, GObject, 和 GNOME 以及其他软件包如Ghostscript和gcc。为了理解后续内容需要了解一个基础库GLiblibglib - 2.0它为GTK 小部件集和GNOME应用程序提供基本的数据结构和实用函数。本章介绍GLib的架构并引入其API。使用GNOME和GTK 时无法避免使用GLib其他库如ORBit也使用GLib而且很多库不依赖其他库。GLib提供的抽象和实用工具对几乎任何编程任务都很有用并且简化了向其他平台的移植。10.2 GLib命名约定GLib有以下命名规则以保证一致性和可读性- 函数名全部小写各部分之间用下划线分隔且所有函数名以g_开头如g_timer_new(),g_list_append()。- 库中的所有函数都有一个共同的前缀在GLib中是g_。- 类型名不包含下划线每个组件以大写字母开头且以G开头如GTimer,GList但第1.3节中的基本类型除外。- 如果一个函数主要操作某种类型其前缀与该类型名对应例如g_timer_*函数用于操作GTimer类型g_list_*函数用于操作GList类型。10.3 基本类型要使用GLib需要适应其基本类型。使用guchar而不是unsigned char在同一平台上可能没有实际区别但如果要在不同平台如Windows和Unix之间导入、导出和交互软件GLib可以为你抽象基本数据类型。要使用GLib及其所有类型需要在源代码中包含glib.h头文件#include glib.hgpointer和gconstpointer类型在与GLib数据结构交互时经常出现它们是无类型的内存指针。在GLib中使用这些指针的函数负责验证类型而不是程序员或编译器。这些类型在回调函数和排序、迭代中使用的相等运算符中进行类型抽象时特别有用。GLib头文件为gboolean类型定义了常量TRUE和FALSE但不建议使用等价运算符与这些常量进行比较应使用if (my_gboolean)而不是if (my_gboolean TRUE)。GLib基本类型与C语言对应类型如下表所示| GLib Type | Corresponding Type in C || — | — || gchar | char || ugchar | unsigned char || gint | int || guint | unsigned int || gshort | short || gushort | unsigned short || glong | long || gulong | unsigned long || gfloat | float || gdouble | double || gint8 | int, 8 bits wide || guint8 | unsigned int, 8 bits wide || gint16 | int, 16 bits wide || guint16 | unsigned int, 16 bits wide || gint32 | int, 32 bits wide || guint32 | unsigned int, 32 bits wide || gint64 | int, 64 bits wide || guint64 | unsigned int, 64 bits wide || gpointer | void, untyped pointer || gconstpointer | const void, constant untyped pointer || gboolean | Boolean value, either TRUE or FALSE |11. GLib基本实用工具11.1 内存管理使用GLib的内存管理例程可以避免一些麻烦它提供了额外的错误检查和诊断功能。与C语言类似操作并不复杂以下是GLib函数与C语言对应函数的参考| GLib Function | Corresponding C Function || — | — || gpointer g_malloc(gulong n_bytes) | voidmalloc(size_t size) with error handling || gpointer g_malloc0(gulong n_bytes) | like malloc(), but initializes memory as in calloc() || gpointer g_try_malloc(gulong n_bytes) | like malloc() without error checking || gpointer g_realloc(gpointer mem, gulong n_bytes) | voidrealloc(voidptr, size_t size) with error checking || gpointer g_try_realloc(gpointer mem, gulong n_bytes) | realloc() without error checking || void g_free(gpointer mem) | void free(voidptr) |如果需要手动检查返回代码可以使用g_try_malloc()和g_try_realloc()它们在失败时返回NULL。对于大多数应用程序像g_malloc()这样的正常函数可以节省大量代码、减少挫折并节省时间。正常做法是不直接为malloc()和g_malloc()等函数指定请求的内存块大小而是让编译器或运行时系统根据类型大小倍数通常使用sizeof()来确定。为了使数据类型一致需要对malloc()的返回值进行强制类型转换。GLib提供了g_new()、g_new0()和g_renew()宏来简化操作示例代码如下typedef struct _footype footype; footype *my_data; /* Allocate space for three footype structures (long version) */ my_data (footype *) g_malloc(sizeof(footype)*3); /* The abbreviated version using g_new */ my_data g_new(footype, 3); /* To initialize the memory to 0, use g_new0 */ my_data g_new0(footype, 3); /* Expand this block of memory to four structures (long version) */ my_data (footype *) g_realloc(my_data, sizeof(footype)*4); /* Shorter version */ my_data g_renew(my_data, 4);需要注意的是使用g_new()时必须使用类型否则会导致编译错误因为g_new()是一个宏。11.2 内存块GUI应用程序倾向于反复分配相同大小的内存块原子且原子的种类相对较少。GLib使用内存块GMemChunk机制为应用程序提供原子。一个内存块由多个原子组成其块大小是组成原子的总字节长度因此块大小必须是原子大小的倍数。以下是使用g_mem_chunk_new()请求新内存块的示例GMemChunk my_chunk; my_chunk g_mem_chunk_new(My Chunk, /* name */ 42, /* atom size */ 42*16, /* block size */ G_ALLOC_AND_FREE); /* access mode */g_mem_chunk_new()函数有四个参数用于诊断的内存块名称、每个原子的大小、整体块大小最好写成原子大小的倍数和访问模式。返回值是指向新GMemChunk结构的指针。访问模式有两种-G_ALLOC_AND_FREE允许随时将单个原子返回内存池。-G_ALLOC_ONLY仅允许在释放整个内存块时释放原子这种模式比G_ALLOC_AND_FREE更高效。以下是在上述示例中创建的内存块中分配和释放内存原子的示例gchar *data[50000]; gint i; /* allocate 40,000 atoms */ for(i 0; i 40000; i) { data[i] g_mem_chunk_alloc(my_chunk); } /* allocate 10,000 more atoms and initialize them */ for(i 40000; i 50000; i) { data[i] g_mem_chunk_alloc0(my_chunk); } /* free one atom */ g_mem_chunk_free(my_chunk, data[42]);g_mem_chunk_alloc()和g_mem_chunk_alloc0()用于分配单个原子它们的工作方式类似于g_malloc()和g_malloc0()但接受GMemChunk结构作为参数而不是大小规格。g_mem_chunk_free()用于将单个原子返回未分配的内存池。需要注意的是只能对使用G_ALLOC_AND_FREE访问模式创建的内存块中的原子使用g_mem_chunk_free()并且永远不要使用g_free()来释放原子否则会导致段错误。还有几个函数可以一次性清理和释放内存块中的原子示例如下/* free up any unused atoms */ g_mem_chunk_clean(my_chunk); /* free all unused atoms in all memory chunks */ g_blow_chunks(); /* deallocate all atoms in a chunk */ g_mem_chunk_reset(my_chunk); /* deallocate a memory chunk */ g_mem_chunk_destroy(my_chunk);这些函数的作用分别是-g_mem_chunk_clean(chunk)检查块并释放任何未使用的内存。-g_blow_chunks()对程序中所有未处理的内存块运行g_mem_chunk_clean()。-g_mem_chunk_reset(chunk)释放块中的所有原子包括正在使用的原子使用时要小心。-g_mem_chunk_destroy(chunk)释放块中的所有原子和内存块本身。与一般的内存管理一样GLib提供了一些宏来节省输入示例如下typedef struct _footype footype; GMemChunk *pile_of_mem; footype *foo; /* create a memory chunk with space for 128 footype atoms */ pile_of_mem g_mem_chunk_new(A pile of memory, sizeof(footype), sizeof(footype)*128, G_ALLOC_AND_FREE);GNOME编程基础与GLib库入门12. 内存管理流程总结为了更清晰地展示GLib内存管理的操作流程下面用mermaid流程图来呈现graph LR classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px A([开始]):::startend -- B{选择内存分配方式}:::decision B --|普通分配| C(使用g_malloc/g_malloc0/g_try_malloc):::process B --|批量相同大小分配| D(使用内存块GMemChunk):::process C -- E{是否需要调整内存大小}:::decision E --|是| F(使用g_realloc/g_try_realloc):::process E --|否| G(继续使用内存):::process D -- H(使用g_mem_chunk_new创建内存块):::process H -- I(选择访问模式):::decision I --|G_ALLOC_AND_FREE| J(可随时释放单个原子):::process I --|G_ALLOC_ONLY| K(只能释放整个内存块时释放原子):::process J -- L(使用g_mem_chunk_alloc/g_mem_chunk_alloc0分配原子):::process K -- L L -- M(使用g_mem_chunk_free释放原子):::process G -- N{是否释放内存}:::decision N --|是| O(使用g_free释放内存):::process M -- P(使用g_mem_chunk_clean/g_blow_chunks/g_mem_chunk_reset/g_mem_chunk_destroy清理或销毁内存块):::process O -- Q([结束]):::startend P -- Q这个流程图总结了GLib中内存管理的主要流程包括普通内存分配、内存块分配以及相应的释放和清理操作。13. GLib其他实用工具展望除了前面介绍的内存管理GLib还有许多其他实用工具等待我们去探索。例如GLib提供了丰富的数据结构操作函数如链表GList、双链表GSList、哈希表GHashTable等。这些数据结构可以帮助我们更高效地组织和处理数据。以链表为例GLib提供了一系列操作链表的函数如g_list_append()用于在链表末尾添加元素g_list_prepend()用于在链表头部添加元素g_list_remove()用于移除链表中的元素等。以下是一个简单的链表操作示例#include glib.h #include stdio.h int main() { GList *list NULL; list g_list_append(list, element1); list g_list_append(list, element2); list g_list_append(list, element3); GList *current list; while (current ! NULL) { printf(%s\n, (char *)current-data); current current-next; } g_list_free(list); return 0; }在这个示例中我们创建了一个链表并向其中添加了三个元素然后遍历链表并打印出每个元素的值最后释放链表占用的内存。14. 总结与建议通过前面的介绍我们了解了GNOME编程的基础要求、GLib库的基本概念和使用方法特别是GLib的内存管理机制。在实际编程中我们可以根据具体需求选择合适的内存分配方式合理使用GLib提供的函数和宏以提高编程效率和代码的健壮性。为了更好地掌握GLib建议大家多阅读GLib的官方文档深入了解其各种功能和用法。同时多进行实践通过编写实际的代码来巩固所学知识。在遇到问题时可以参考GLib的文档和社区论坛寻求帮助和解决方案。以下是一些具体的建议- 对于初学者先从简单的示例代码开始逐步理解GLib的基本概念和操作。- 在使用内存管理函数时要注意错误处理避免内存泄漏和段错误。- 当需要处理大量相同大小的内存块时优先考虑使用内存块机制以提高内存分配和释放的效率。- 多参考优秀的开源项目学习他人的编程经验和技巧。希望大家在GNOME编程和GLib库的学习中取得良好的进展开发出高质量的应用程序