1. 简介
GLib-2.0的GLib部分提供了许多有用的数据类型、宏、类型转换、字符串实用程序、文件实用程序、主循环抽象等等,具体包含:字符串操作、文件操作、数据校验、编解码、字符集转换、随机数生成器、命令行解析器、xml解析器、正则表达式、单链表、双链表、 数组、指针数组、双端队列、哈希表、平衡二叉树、N维树、泛型、主循环、多线程、线程池、异步队列、内存分配、内存片段、错误系统、测试框架等等一系列功能。
2. 环境搭建
2.1 下载安装
下载链接:
wget http://ftp.acc.umu.se/pub/GNOME/sources/glib/2.45/glib-2.45.2.tar.xz
解压:
tar -xf glib-2.45.2.tar.xz
编译:
cd ./glib-2.45.2
./configure
make
make install
编译问题解决:
- zlib库问题
configure: error: *** Working zlib library and headers not found ***
解决:
yum install libffi-devel
2.2 配置glib库开发环境
- 配置PATH环境变量
vi /etc/profile //添加内容如下
export PATH=/usr/local/glib/bin:$PATH
- 配置glib第三方库的C的头文件搜索路径
vi ~/.bash_profile
C_GLIB_PATH=/usr/local/glib/include/glib-2.0:/usr/local/glib/lib/glib-2.0/include
export C_INCLUDE_PATH=$C_GLIB_PATH:$C_INCLUDE_PATH
- 配置glib三方库的链接库文件搜索路径
vi ~/.bash_profile
export LD_LIBRARY_PATH=/usr/local/glib/lib:$LD_LIBRARY_PATH
export LIBRARY_PATH=/usr/local/glib/lib:$LIBRARY_PATH
2.3 测试验证
gcc glib_version.c -o glib_version -lglib-2.0
/*
**程序描述:获取glib库的版本号。
*/
#include <glib.h>
int main()
{
const gchar *str;
str=glib_check_version(GLIB_MAJOR_VERSION,GLIB_MINOR_VERSION,GLIB_MICRO_VERSION);
if(str!=NULL)
g_print("%s\n",str);
g_print("Current Glib Version: %u.%u.%u\n", GLIB_MAJOR_VERSION,GLIB_MINOR_VERSION,GLIB_MICRO_VERSION);
return 0;
}
3. glib库的使用
3.1 数据结构
3.1.1 字符串
gchar* g_strdup(const gchar* str);
// 功能:复制字符串
// 参数:要复制的字符串
// 返回值:复制后的新字符串
// 示例:
const gchar* original = "Hello, world!";
gchar* duplicate = g_strdup(original);
g_print("Duplicate string: %s\n", duplicate);
gchar* g_strjoin(const gchar* separator, ...);
// 功能:连接多个字符串
// 参数1:用于分隔各个字符串的分隔符
// 可变参数:要连接的多个字符串,以 NULL 结尾
// 返回值:连接后的新字符串
// 示例:
const gchar* str1 = "Hello";
const gchar* str2 = "world!";
gchar* result = g_strjoin(" ", str1, str2, NULL);
g_print("Joined string: %s\n", result);
gint g_strcmp0(const gchar* str1, const gchar* str2);
// 功能:比较字符串
// 参数1:第一个要比较的字符串
// 参数2:第二个要比较的字符串
// 返回值:0 表示字符串相等,正数表示 str1 大于 str2,负数表示 str1 小于 str2
// 示例:
const gchar* str1 = "abc";
const gchar* str2 = "def";
gint result = g_strcmp0(str1, str2);
if (result == 0) {
g_print("Strings are equal\n");
} else if (result > 0) {
g_print("str1 is greater than str2\n");
} else {
g_print("str1 is less than str2\n");
}
gchar** g_strsplit(const gchar* string, const gchar* delimiter, gint max_tokens);
// 功能:将字符串拆分为子字符串数组
// 参数1:要拆分的字符串
// 参数2:用于指定拆分位置的分隔符
// 参数3:最大拆分数,-1 表示不限制拆分数
// 返回值:拆分后的字符串数组
// 示例:
const gchar* string = "Hello,world,!";
const gchar* delimiter = ",";
gchar** tokens = g_strsplit(string, delimiter, -1);
for (gint i = 0; tokens[i] != NULL; i++) {
g_print("Token %d: %s\n", i, tokens[i]);
}
g_strfreev(tokens); // 释放拆分后的字符串数组
const gchar* g_strstr_len(const gchar* haystack, gssize haystack_len, const gchar* needle);
// 功能:在指定长度的字符串中查找子字符串
// 参数1:要查找的字符串
// 参数2:字符串的长度
// 参数3:要查找的子字符串
// 返回值:指向子字符串在字符串中的位置的指针,或者 NULL 表示未找到
// 示例:
const gchar* haystack = "Hello, world!";
const gchar* needle = "world";
const gchar* result = g_strstr_len(haystack, -1, needle);
if (result != NULL) {
g_print("Substring found at position: %ld\n", result - haystack);
} else {
g_print("Substring not found\n");
}
3.1.2 单链表
GSList* g_slist_alloc (void);
// 功能:分配一个新的单链表
// 返回值:分配的单链表的指针
GSList* g_slist_append (GSList *list, gpointer data);
// 功能:将元素添加到单链表的末尾
// 参数1:要添加元素的单链表
// 参数2:要添加的元素数据
// 返回值:更新后的单链表的指针
GSList* g_slist_prepend (GSList *list, gpointer data);
// 功能:将元素添加到单链表的开头
// 参数1:要添加元素的单链表
// 参数2:要添加的元素数据
// 返回值:更新后的单链表的指针
GSList* g_slist_insert (GSList *list, gpointer data, gint position);
// 功能:在指定位置插入元素到单链表中
// 参数1:要插入元素的单链表
// 参数2:要插入的元素数据
// 参数3:要插入的位置(从0开始计数)
// 返回值:更新后的单链表的指针
GSList* g_slist_remove (GSList *list, gconstpointer data);
// 功能:从单链表中移除指定的元素
// 参数1:要移除元素的单链表
// 参数2:要移除的元素数据
// 返回值:更新后的单链表的指针
GSList* g_slist_remove_all (GSList *list, gconstpointer data);
// 功能:从单链表中移除所有与指定元素匹配的元素
// 参数1:要移除元素的单链表
// 参数2:要移除的元素数据
// 返回值:更新后的单链表的指针
void g_slist_free (GSList *list);
// 功能:释放单链表及其元素的内存
// 参数:要释放的单链表
guint g_slist_length (GSList *list);
// 功能:获取单链表的长度(元素个数)
// 参数:要获取长度的单链表
// 返回值:单链表的长度
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <glib.h>
int main()
{
GSList *slist = NULL;
GSList *st;
int nums[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i;
for (i = 0; i < 10; i++) {
//尾插法添加数据
slist = g_slist_append(slist, &nums[i]);
}
//插入数据7表示插入位置,8表示插入数值
slist = g_slist_insert(slist, &nums[8], 7);
slist = g_slist_reverse(slist); //翻转链表
//根据元素删除
slist = g_slist_remove(slist, &nums[8]);
for (i = 0; i < 10; i++) {
//头插法添加数据
slist = g_slist_prepend(slist, &nums[i]);
}
for (i = 0; i < 11; i++) {
//打印数据
st = g_slist_nth(slist, i);
g_printf("%d ", *(gint *)st->data);
}
g_printf("\n");
g_slist_free(slist);
return 0;
}
9 8 7 6 5 4 3 2 1 0 9
3.1.3 动态数组
- 数组类似于标准 C 数组,不同之处在于它们会自动增长 作为元素的添加。
- 数组元素可以是任何大小(尽管一个数组的所有元素都是 大小相同),数组可以自动清除为'0'和 零端接。
- 要创建新数组,请使用 g_array_new()。
- 若要向数组添加元素,请使用 g_array_append_val()、g_array_append_vals()、g_array_prepend_val() 和 g_array_prepend_vals()。
- 要访问数组的元素,请使用 g_array_index()。
- 要设置数组的大小,请使用 g_array_set_size()。
- 要释放数组,请使用 g_array_free()。
typedef struct {
gchar * data;
guint len;
} GArray;
GArray* g_array_new (gboolean zero_terminated, gboolean clear_, guint element_size);
// 功能: 新建一个数组
// 参数1: 如果数组末尾应该有一个额外的元素,则为TRUE。 设置为 0
// 参数2: 如果应自动清除 GArray 元素,则为TRUE当它们被分配时
// 参数3: 每个元素的大小(以字节为单位)
// 返回值:GArray*
GArray* g_array_sized_new (gboolean zero_terminated,gboolean clear_, guint element_size, guint reserved_size);
// 功能: 新建一个数组 (避免频繁重新分配空间)
// 参数1: 如果数组末尾应该有一个额外的元素,则为 TRUE。 设置为 0
// 参数2: 如果应自动清除 GArray 元素,则为 TRUE 当它们被分配时
// 参数3: 每个元素的大小(以字节为单位)
// 参数4: 预分配的元素数
// 返回值:GArray*
#define g_array_append_val (a,v)
GArray* g_array_append_vals (GArray *array, gconstpointer data, guint len);
// 功能: 将 len 元素添加到数组的末尾
// 参数1:数组指针
// 参数2:指向要追加到数组末尾的元素的指针
// 参数3:要追加的元素数
// 返回值:GArray*
#define g_array_prepend_val (a,v)
GArray* g_array_prepend_vals (GArray *array, gconstpointer data, guint len);
//功能: 将 len 元素添加到数组的开头 (比尾插慢,需要移动数据)
// 参数1:数组指针
// 参数2:指向要追加到数组末尾的元素的指针
// 参数3:要追加的元素数
// 返回值:GArray*
#define g_array_insert_val (a,i,v)
GArray* g_array_insert_vals (GArray *array, guint index_, gconstpointer data, guint len);
// 功能: 将元素插入到给定索引处的数组中
// 参数1:数组指针
// 参数2:要放置元素的索引
// 参数3:指向要插入的元素的指针
// 参数4:要插入的元素数
// 返回值:GArray*
GArray* g_array_remove_index (GArray *array, guint index_);
// 功能: 从 GArray 中删除给定索引处的元素。 以下元素下移一个位置。
// 参数1:数组指针
// 参数2:要删除的元素的索引
// 返回值:GArray*
GArray* g_array_remove_index_fast (GArray *array, guint index_);
// 功能:从 GArray 中删除给定索引处的元素。数组中的最后一个元素用于填充空格,因此此函数不保留 GArray 的顺序。但它比 g_array_remove_index快。
// 参数1:数组指针
// 参数2:要删除的元素的索引
// 返回值:GArray*
GArray* g_array_remove_range (GArray *array, guint index_, guint length);
// 功能: 从 GArray 中删除从给定索引开始的给定数量的元素。移动以下元素以缩小差距。
// 参数1:数组指针
// 参数2:要删除的第一个元素的索引
// 参数3:要删除的元素数
// 返回值:GArray*
void g_array_sort (GArray *array, GCompareFunc compare_func);
// 功能:使用 compare_func 对 GArray 进行排序,这应该是--样式比较函数(返回小于零的第一个参数小于第二个参数,
// 零表示相等,如果第一个参数大于第二个参数,则大于)。qsort()
// 参数1:数组指针
// 参数2:比较功能
void g_array_sort_with_data (GArray *array, GCompareDataFunc compare_func, gpointer user_data);
// 功能: 与g_array_sort()类似,但比较函数接收额外的用户数据论点。
// 参数1:数组指针
// 参数2:比较功能
// 返回值:要传递给compare_func的数据
#define g_array_index (a,t,i)
GArray* g_array_set_size (GArray *array, guint length);
// 功能: 设置数组的大小,必要时展开它。 如果创建的数组clear_设置为 TRUE,则新元素设置为 0。
// 参数1:数组指针
// 参数2:GArray 的新大小。
// 返回值:GArray*
gchar* g_array_free (GArray *array, gboolean free_segment);
// 功能: 释放为 GArray分配的内存
// 如果free_segment为TRUE,则释放保存元素的内存块 也。
// 传递 FALSE 如果你想释放GArray包装器但保留用于其他地方的基础数组。
// 参数1:数组指针
// 参数2:如果为 TRUE,则实际元素数据也会被释放
// 返回值:元素数据(如果free_segment为FALSE,否则为 NULL。 应使用 g_free() 释放元素数据。
#include <stdio.h>
#include <glib.h>
// 比较函数,用于排序
gint compare_func(gconstpointer a, gconstpointer b) {
gint value_a = *((gint*)a);
gint value_b = *((gint*)b);
return value_b - value_a;
}
int main() {
int i = 0;
//创建动态数组
GArray* garray = g_array_new(FALSE, FALSE, sizeof(int));
// 向动态数组中添加元素
for (i = 0; i < 10; i++) {
g_array_append_val(garray, i);
}
// 遍历并打印动态数组的元素
for (i = 0; i < garray->len; i++)
{
int val = g_array_index(garray, int, i);
printf("%d ", val);
}
printf("\n");
// 修改动态数组中的元素
g_array_index(garray, int, 5) = 42;
// 排序动态数组
g_array_sort(garray, compare_func);
// 遍历并打印动态数组的元素
for (i = 0; i < garray->len; i++)
{
int val = g_array_index(garray, int, i);
printf("%d ", val);
}
printf("\n");
// 释放动态数组的内存
g_array_free(garray, TRUE);
return 0;
}
0 1 2 3 4 5 6 7 8 9
42 9 8 7 6 4 3 2 1 0
3.1.4 哈希表
GHashTable* g_hash_table_new (GHashFunc hash_func, GEqualFunc key_equal_func);
// 功能:创建一个新的哈希表
// 参数1:哈希函数,用于计算键的哈希值
// 参数2:键相等函数,用于比较键的相等性
// 返回值:新创建的哈希表的指针
void g_hash_table_insert (GHashTable *hash_table, gpointer key, gpointer value);
// 功能:向哈希表中插入键值对
// 参数1:要插入的哈希表
// 参数2:要插入的键
// 参数3:要插入的值
gboolean g_hash_table_contains (GHashTable *hash_table, gconstpointer key);
// 功能:检查哈希表中是否包含指定的键
// 参数1:要检查的哈希表
// 参数2:要检查的键
// 返回值:如果哈希表包含指定的键,则返回TRUE;否则返回FALSE
gpointer g_hash_table_lookup (GHashTable *hash_table, gconstpointer key);
// 功能:查找指定键在哈希表中对应的值
// 参数1:要查找的哈希表
// 参数2:要查找的键
// 返回值:键对应的值,如果键不存在,则返回NULL
gboolean g_hash_table_lookup_extended (GHashTable *hash_table, gconstpointer lookup_key, gpointer *orig_key, gpointer *value);
// 功能:查找指定键的值,并返回键、值以及是否找到的信息
// 参数1:要查找的哈希表
// 参数2:要查找的键
// 参数3:用于接收原始键的指针变量
// 参数4:用于接收键对应的值的指针变量
// 返回值:如果找到了指定键,则返回TRUE;否则返回FALSE
void g_hash_table_remove (GHashTable *hash_table, gconstpointer key);
// 功能:从哈希表中移除指定的键及其对应的值
// 参数1:要移除键值对的哈希表
// 参数2:要移除的键
void g_hash_table_destroy (GHashTable *hash_table);
// 功能:销毁哈希表,并释放相关的内存
// 参数:要销毁的哈希表
#include <stdio.h>
#include <glib.h>
int main() {
GHashTable *hashTable = g_hash_table_new(g_str_hash, g_str_equal);
// 向哈希表中插入键值对
g_hash_table_insert(hashTable, "key1", "value1");
g_hash_table_insert(hashTable, "key2", "value2");
g_hash_table_insert(hashTable, "key3", "value3");
// 查找指定键的值
const gchar *value = g_hash_table_lookup(hashTable, "key2");
if (value != NULL) {
printf("Value for key2: %s\n", value);
}
// 查找指定键的值和键
{
gpointer key = NULL;
gpointer value = NULL;
gboolean found = g_hash_table_lookup_extended(hashTable, "key2", &key, &value);
if (found) {
printf("Found key2: Key: %s, Value: %s\n", (gchar*)key, (gchar*)value);
} else {
printf("Key2 not found\n");
}
}
// 从哈希表中移除键值对
g_hash_table_remove(hashTable, "key3");
// 销毁哈希表
g_hash_table_destroy(hashTable);
return 0;
}
Value for key2: value2
Found key2: Key: key2, Value: value2
3.2 base64编解码
gchar* g_base64_encode (const guchar *data, gsize len);
// 功能:对给定数据进行Base64编码
// 参数1:要编码的数据
// 参数2:数据的长度
// 返回值:Base64编码后的字符串
guchar* g_base64_decode (const gchar *str, gsize *out_len);
// 功能:对给定的Base64编码字符串进行解码
// 参数1:要解码的Base64编码字符串
// 参数2:用于返回解码后数据的长度
// 返回值:解码后的数据
gchar* g_base64_encode_inplace (guchar *data, gsize len);
// 功能:对给定数据进行原地(in-place)Base64编码
// 参数1:要编码的数据
// 参数2:数据的长度
// 返回值:Base64编码后的字符串(与输入数据指向同一地址)
guchar* g_base64_decode_inplace (gchar *str, gsize *out_len);
// 功能:对给定的Base64编码字符串进行原地(in-place)解码
// 参数1:要解码的Base64编码字符串
// 参数2:用于返回解码后数据的长度
// 返回值:解码后的数据(与输入字符串指向同一地址)
gsize g_base64_encode_step (const guchar *data, gsize len, gboolean break_lines, gchar *result, gint *state, gint *save);
// 功能:对给定数据进行Base64编码的步进式操作
// 参数1:要编码的数据
// 参数2:数据的长度
// 参数3:是否在编码结果中插入换行符
// 参数4:存储编码结果的缓冲区
// 参数5:编码操作的状态
// 参数6:编码操作的保存值
// 返回值:编码结果的长度
gsize g_base64_decode_step (const gchar *str, gsize len, guchar *result, gint *state, guint *save);
// 功能:对给定的Base64编码字符串进行解码的步进式操作
// 参数1:要解码的Base64编码字符串
// 参数2:字符串的长度
// 参数3:存储解码结果的缓冲区
// 参数4:解码操作的状态
// 参数5:解码操作的保存值
// 返回值:解码结果的长度
#include <stdio.h>
#include <glib.h>
int main() {
const gchar *data = "Hello, World!";
gsize len = strlen(data);
// Base64 编码
gchar *encoded = g_base64_encode((const guchar *)data, len);
printf("Base64 Encoded: %s\n", encoded);
// Base64 解码
gsize decoded_len = 0;
guchar *decoded = g_base64_decode(encoded, &decoded_len);
printf("Base64 Decoded: %.*s\n", (int)decoded_len, decoded);
// 释放内存
g_free(encoded);
g_free(decoded);
return 0;
}
Base64 Encoded: SGVsbG8sIFdvcmxkIQ==
Base64 Decoded: Hello, World!
3.3 数据完整校验
GChecksum* g_checksum_new(GChecksumType checksum_type);
// 功能:创建一个新的校验和对象
// 参数:校验和类型,可选值为 G_CHECKSUM_MD5、G_CHECKSUM_SHA1 等
// 返回值:新创建的校验和对象
void g_checksum_update(GChecksum *checksum, const guchar *data, gssize length);
// 功能:更新校验和
// 参数1:校验和对象
// 参数2:要更新的数据
// 参数3:要更新的数据的长度
void g_checksum_get_digest(GChecksum *checksum, guint8 *buffer, gsize *digest_len);
// 功能:获取校验和的结果
// 参数1:校验和对象
// 参数2:缓冲区,用于存储校验和结果
// 参数3:指向存储校验和结果长度的变量的指针
void g_checksum_free(GChecksum *checksum);
// 功能:释放校验和对象
// 参数:校验和对象
#include <glib.h>
int main() {
// 创建 MD5 校验和对象
GChecksum* checksum = g_checksum_new(G_CHECKSUM_MD5);
// 数据分块
const guchar* data1 = (const guchar*)"Hello, ";
const guchar* data2 = (const guchar*)"world!";
gssize length1 = strlen((const gchar*)data1);
gssize length2 = strlen((const gchar*)data2);
// 分块更新校验和
g_checksum_update(checksum, data1, length1);
g_checksum_update(checksum, data2, length2);
// 获取最终校验和
gsize digest_length = 16; // MD5 校验和长度为 16 字节
guint8 digest[16]; // 创建缓冲区来存储校验和结果
g_checksum_get_digest(checksum, digest, &digest_length);
g_print("MD5 digest: ");
guint i;
for (i = 0; i < digest_length; i++) {
g_print("%02x", digest[i]);
}
g_print("\n");
// 释放校验和对象
g_checksum_free(checksum);
return 0;
}
MD5 digest: 6cd3556deb0da54bca060b4c39479839
3.4 定时器
GSource* g_timeout_source_new(guint interval);
// 功能:创建一个基于时间的新源对象(定时器)
// 参数:定时器的触发间隔(以毫秒为单位)
// 返回值:新创建的源对象(定时器)
GSource* g_timeout_source_new_seconds(guint interval);
// 功能:创建一个基于时间的新源对象(定时器)
// 参数:定时器的触发间隔(以秒为单位)
// 返回值:新创建的源对象(定时器)
guint g_timeout_add(guint interval, GSourceFunc function, gpointer data);
// 功能:将函数添加为基于时间的源对象(定时器)的回调函数
// 参数1:定时器的触发间隔(以毫秒为单位)
// 参数2:回调函数,当定时器触发时调用
// 参数3:传递给回调函数的用户数据
// 返回值:用于标识定时器的ID
guint g_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
// 功能:将函数添加为基于时间的源对象(定时器)的回调函数
// 参数1:定时器的触发间隔(以秒为单位)
// 参数2:回调函数,当定时器触发时调用
// 参数3:传递给回调函数的用户数据
// 返回值:用于标识定时器的ID
void g_source_destroy(GSource* source);
// 功能:销毁源对象
// 参数:要销毁的源对象(定时器)
gboolean g_source_remove(guint id);
// 功能:从主循环中移除源对象(定时器)
// 参数:要移除的源对象的ID
// 返回值:如果成功移除则为TRUE,否则为FALSE
guint g_timeout_add_full(gint priority, guint interval, GSourceFunc function, gpointer data, GDestroyNotify notify);
// 功能:以指定的优先级创建一个基于时间的源对象(定时器)并添加回调函数
// 参数1:源对象的优先级
// 参数2:定时器的触发间隔(以毫秒为单位)
// 参数3:回调函数,当定时器触发时调用
// 参数4:传递给回调函数的用户数据
// 参数5:在定时器被移除时调用的销毁通知函数
// 返回值:用于标识定时器的ID
#include <stdio.h>
#include <glib.h>
gboolean timer1_callback(gpointer data) {
printf("Timer 1 callback called.\n");
return TRUE;
}
gboolean timer2_callback(gpointer data) {
printf("Timer 2 callback called.\n");
return TRUE;
}
int main() {
guint timer1_id, timer2_id;
// 创建定时器1,每隔1秒触发一次
timer1_id = g_timeout_add(1000, timer1_callback, NULL);
printf("Timer 1 created. Timer ID: %u\n", timer1_id);
// 创建定时器2,每隔2秒触发一次
timer2_id = g_timeout_add(2000, timer2_callback, NULL);
printf("Timer 2 created. Timer ID: %u\n", timer2_id);
// 启动主循环以触发定时器回调
g_main_loop_run(g_main_loop_new(NULL, FALSE));
// 移除定时器1
g_source_remove(timer1_id);
printf("Timer 1 removed.\n");
// 移除定时器2
g_source_remove(timer2_id);
printf("Timer 2 removed.\n");
return 0;
}
Timer 1 created. Timer ID: 1
Timer 2 created. Timer ID: 2
Timer 1 callback called.
Timer 1 callback called.
Timer 2 callback called.