glib库是Linux平台下最经常使用的C语言函数库,它具备很好的可移植性和实用性。glib是Gtk+库和Gnome的基础。glib能够在多个平台 下使用,好比Linux、Unix、Windows等。glib为许多标准的、经常使用的C语言结构提供了相应的替代物。若是有什么东西本书没有介绍到,请参 考glib的头文件:glib.h。glib.h中的头文件很容易理解,不少函数从字面上都能猜出它的用处和用法。若是有兴趣,glib的源代码也是很是 好的学习材料。
glib的各类实用程序具备一致的接口。它的编码风格是半面向对象,标识符加了一个前缀“g”,这也是一种通行的命名约定。node
使用glib库的程序都应该包含glib的头文件glib.h。若是程序已经包含了gtk.h或gnome.h,则不须要再包含glib.h。程序员
3.1类型定义编程
glib的类型定义不是使用C的标准类型,它本身有一套类型系统。它们比经常使用的C语言的类型更丰富,也更安全可靠。引进这套系统是为了多种缘由。例如, gint32能保证是32位的整数,一些不是标准C的类型也能保证。有一些仅仅是为了输入方便,好比guint比unsigned更容易输入。还有一些仅 仅是为了保持一致的命名规则,好比,gchar和char是彻底同样的。数组
如下是glib基本类型定义:安全
整数类型:gint八、guint八、gint1六、guint1六、gint3二、guint3二、gint6四、guint64。其中gint8是8位的整数,guint8是8位的无符号整数,其余依此类推。这些整数类型可以保证大小。数据结构
不是全部的平台都提供64位整型,若是一个平台有这些,glib会定义G_HAVE_GINT64。整数类型gshort、glong、gint和 short、long、int彻底等价。布尔类型gboolean:它可以使代码更易读,由于普通C没有布尔类型。Gboolean能够取两个值:TRUE 和FALSE。实际上FALSE定义为0,而TRUE定义为非零值。app
字符型gchar和char彻底同样,只是为了保持一致的命名。函数
浮点类型gfloat、gdouble和float、double彻底等价。工具
指针gpointer对应于标准C的void*,可是比void*更方便。post
指针gconstpointer对应于标准C的constvoid*(注意,将constvoid*定义为constgpointer是行不通的)。
3.2glib的宏
3.2.1经常使用宏
glib定义了一些在C程序中常见的宏,详见下面的列表。TRUE/FALSE/NULL就是第二部分Linux编程经常使用C语言函数库及构件库1/0/ ((void*)0)。MIN()/MAX()返回更小或更大的参数。ABS()返回绝对值。CLAMP(x,low,
high)若X在[low,high]范围内,则等于X;若是X小于low,则返回low;若是X大于high,则返回high。
一些经常使用的宏列表
#include<glib.h>
TRUE
FALSE
NULL
MAX(a,b)
MIN(a,b)
ABS(x)
CLAMP(x,low,high)
有些宏只有glib拥有,例如在后面要介绍的gpointer-to-gint和gpointer-to-guint。大多数glib的数据结构都设计 成存储一个gpointer。若是想存储指针来动态分配对象,能够这样作。然而,有时仍是想存储一列整数而不想动态地分配它们。虽然C标准不能严格保证, 可是在多数glib支持的平台上,在gpointer变量中存储gint或guint还是可能的。在某些状况下,须要使用中间类型转换。
下面是示例:
gintmy_int;
gpointermy_pointer;
my_int=5;
my_pointer=GINT_TO_POINTER(my_int);
printf("Wearestoring%d\n",GPOINTER_TO_INT(my_pointer));
这些宏容许在一个指针中存储一个整数,但在一个整数中存储一个指针是不行的。若是要实现的话,必须在一个长整型中存储指针。
宏列表:在指针中存储整数的宏
#include<glib.h>
GINT_TO_POINTER(p)
GPOINTER_TO_INT(p)
GUINT_TO_POINTER(p)
GPOINTER_TO_UINT(p)
3.2.2调试宏
glib提供了一整套宏,在你的代码中使用它们能够强制执行不变式和前置条件。这些宏很稳定,也容易使用,于是Gtk+大量使用它们。定义了 G_DISABLE_CHECKS或G_DISABLE_ASSERT以后,编译时它们就会消失,因此在软件代码中使用它们不会有性能损失。大量使用它们 可以更快速地发现程序的错误。发现错误后,为确保错误不会在之后的版本中出现,能够添加断言和检查。特别是当编写的代码被其余程序员看成黑盒子使用时,
这种检查颇有用。用户会马上知道在调用你的代码时发生了什么错误,而不是猜想你的代码中有什么缺陷。
固然,应该确保代码不是依赖于一些只用于调试的语句才能正常工做。若是一些语句在生成代码时要取消,这些语句不该该有任何反作用。
宏列表:前提条件检查
#include<glib.h>
g_return_if_fail(condition)
g_return_val_if_fail(condition,retval)
这个宏列表列出了glib的预条件检查宏。对g_return_if_fail(),若是条件为假,则打印一个警告信息而且从当前函数马上返回。 g_return_val_if_fail()与前一个宏相似,可是容许返回一个值。毫无疑问,这些宏颇有用—若是大量使用它们,特别是结合Gtk+的实 时类型检查,会节省大量的查找指针和类型错误的时间。
使用这些函数很简单,下面的例子是glib中哈希表的实现:
void
g_hash_table_foreach(GHashTable*hash_table,
GHFuncfunc,
gpointeruser_data)
{
GHashNode*node;
ginti;
g_return_if_fail(hash_table!=NULL);
g_return_if_fail(func!=NULL);
for(i=0;i<hash_table->size;i++)
for(node=hash_table->nodes[i];node;node=node->next)
(*func)(node->key,node->value,user_data);
}
若是不检查,这个程序把NULL做为参数时将致使一个奇怪的错误。库函数的使用者可能要经过调试器找出错误出如今哪里,甚至要到glib的源代码中查找代码的错误是什么。使用这种前提条件检查,他们将获得一个很不错的错误信息,告之不容许使用NULL参数。
宏列表:断言
#include<glib.h>
g_assert(condition)
g_assert_not_reached()
glib也有更传统的断言函数。g_assert()基本上与assert()同样,可是对G_DISABLE_ASSERT
响应(若是定义了G_DISABLE_ASSERT,则这些语句在编译时不编译进去),以及在全部平台上行为都是一致的。还有一个 g_assert_not_reached(),若是执行到这个语句,它会调用abort()退出程序而且(若是环境支持)转储一个可用于调试的core 文件。
应该断言用来检查函数或库内部的一致性。g_return_if_fail()确保传递到程序模块的公用 接口的值是合法的。也就是说,若是断言失败,将返回一条信息,一般应该在包含断言的模块中查找错误;若是g_return_if_fail()检查失败, 一般要在调用这个模块的代码中查找错误。这也是断言与前提条件检查的区别。
下面glib日历计算模块的代码说明了这种差异:
GDate*
g_date_new_dmy(GDateDayday,GDateMonthm,GDateYeary)
{
GDate*d;
g_return_val_if_fail(g_date_valid_dmy(day,m,y),NULL);
d=g_new(GDate,1);
d->julian=FALSE;
d->dmy=TRUE;
d->month=m;
d->day=day;
d->year=y;
g_assert(g_date_valid(d));
returnd;
}
开始的预条件检查确保用户传递合理的年月日值;结尾的断言确保glib构造一个健全的对象,输出健全的值。断言函数g_assert_not_reached()用来标识“不可能”的状况,一般用来检测不能处理的全部可能枚举值的switch语句:
switch(val)
{
caseFOO_ONE:
break;
caseFOO_TWO:
break;
default:
/*无效枚举值*/
g_assert_not_reached();
break;
}
全部调试宏使用glib的g_log()输出警告信息,g_log()的警告信息包含发生错误的应用程序或库函数名字,而且还可使用一个替代的警告打印例程。例如,能够将全部警告信息发送到对话框或log文件而不是输出到控制台。
########################### 内存管理 ##############################
glib用本身的g_变体包装了标准的malloc()和free(),即g_malloc()和g_free()。
它们有如下几个小优势:
* g_malloc()老是返回gpointer,而不是char *,因此没必要转换返回值。
* 若是低层的malloc()失败,g_malloc()将退出程序,因此没必要检查返回值是不是NULL。
* g_malloc() 对于分配0字节返回NULL。
* g_free()忽略任何传递给它的NULL指针。
函数列表: glib内存分配
#include <glib.h>
gpointer g_malloc(gulong size)
void g_free(gpointer mem)
gpointer g_realloc(gpointer mem,gulong size)
gpointer g_memdup(gconstpointer mem,guint bytesize)
g_realloc()和realloc()是等价的。
g_malloc0(),它将分配的内存每一位都设置为0;
g_memdup()返回一个从mem开始的字节数为bytesize的拷贝。
为了与g_malloc()一致,g_realloc()和g_malloc0()均可以分配0字节内存。
g_memdup()在分配的原始内存中填充未设置的位,而不是设置为数值0。
宏列表:内存分配宏
#include <glib.h>
g_new(type, count)
g_new0(type, count)
g_renew(type, mem, count)
########################### 字符串处理 ##############################
若是须要比gchar *更好的字符串,glib提供了一个GString类型。
函数列表: 字符串操做
#include <glib.h>
gint g_snprintf(gchar* buf,gulong n,const gchar* format,. . . )
gint g_strcasecmp(const gchar* s1,const gchar* s2)
gint g_strncasecmp(const gchar* s1,const gchar* s2,guint n)
在含有snprintf()的平台上,g_snprintf()封装了一个本地的snprintf(),而且比原有实现更稳定、安全。
以往的snprintf()不保证它所填充的缓冲是以NULL结束的,但g_snprintf()保证了这一点。
g_snprintf函数在buf参数中生成一个最大长度为n的字符串。其中format是格式字符串,“...”是要插入的参数。
函数列表: 修改字符串
#include <glib.h>
void g_strdown(gchar* string)
void g_strup(gchar* string)
void g_strreverse(gchar* string)
gchar* g_strchug(gchar* string)
gchar* g_strchomp(gchar* string)
宏g_strstrip()结合以上两个函数,删除字符串先后的空格。
函数列表: 字符串转换
#include <glib.h>
gdouble g_strtod(const gchar* nptr,gchar** endptr)
gchar* g_strerror(gint errnum)
gchar* g_strsignal(gint signum)
函数列表: 分配字符串
#include <glib.h>
gchar * g_strdup(const gchar* str)
gchar* g_strndup(const gchar* format,guint n)
gchar* g_strdup_printf(const gchar* format,. . . )
gchar* g_strdup_vprintf(const gchar* format,va_list args)
gchar* g_strescape(gchar* string)
gchar* g_strnfill(guint length,gchar fill_char)
/////////////////////////////////////////////////////////////////////////
gchar* str = g_malloc(256);
g_snprintf(str, 256, "%d printf-style %s", 1, "format");
用下面的代码,不需计算缓冲区的大小:
gchar* str = g_strdup_printf("%d printf-style %", 1, "format") ;
/////////////////////////////////////////////////////////////////////////
函数列表:链接字符串的函数
#include <glib.h>
gchar* g_strconcat(const gchar* string1,. . . )
gchar* g_strjoin(const gchar* separator,. . . )
函数列表: 处理以NULL结尾的字符串向量
#include <glib.h>
gchar** g_strsplit(const gchar* string,const gchar* delimiter,gint max_tokens)
gchar* g_strjoinv(const gchar* separator,gchar** str_array)
void g_strfreev(gchar** str_array)
########################### 数据结构 ##############################
链表~~~~~~~~~~
glib提供了普通的单向链表和双向链表,分别是GSList 和GList。
建立链表、添加一个元素的代码:
GSList* list = NULL;
gchar* element = g_strdup("a string");
list = g_slist_append(list, element);
删除上面添加的元素并清空链表:
list = g_slist_remove(list, element);
为了清除整个链表,可以使用g_slist_free(),它会快速删除全部的连接;
g_slist_free()只释放链表的单元,它并不知道怎样操做链表内容。
访问链表的元素,能够直接访问GSList结构:
gchar* my_data = list->data;
为了遍历整个链表,能够以下操做:
GSList* tmp = list;
while (tmp != NULL)
{
printf("List data: %p\n", tmp->data);
tmp = g_slist_next(tmp);
}
/////////////////////////////////////////////////////////////////////////////
下面的代码能够用来有效地向链表中添加数据:
void efficient_append(GSList** list, GSList** list_end, gpointer data)
{
g_return_if_fail(list != NULL);
g_return_if_fail(list_end != NULL);
if (*list == NULL)
{
g_assert(*list_end == NULL);
*list = g_slist_append(*list, data);
*list_end = *list;
}
else
{
*list_end = g_slist_append(*list_end, data)->next;
}
}
要使用这个函数,应该在其余地方存储指向链表和链表尾的指针,并将地址传递给efficient_append ():
GSList* list = NULL;
GSList* list_end = NULL;
efficient_append(&list, &list_end, g_strdup("Foo"));
efficient_append(&list, &list_end, g_strdup("Bar"));
efficient_append(&list, &list_end, g_strdup("Baz"));
//////////////////////////////////////////////////////////////////////////////
函数列表:改变链表内容
#include <glib.h>
/* 向链表最后追加数据,应将修改过的链表赋给链表指针* /
GSList* g_slist_append(GSList* list,gpointer data)
/* 向链表最前面添加数据,应将修改过的链表赋给链表指针* /
GSList* g_slist_prepend(GSList* list,gpointer data)
/* 在链表的position位置向链表插入数据,应将修改过的链表赋给链表指针* /
GSList* g_slist_insert(GSList* list,gpointer data,gint position)
/ *删除链表中的data元素,应将修改过的链表赋给链表指针* /
GSList* g_slist_remove(GSList* list,gpointer data)
访问链表元素可使用下面的函数列表中的函数。
这些函数都不改变链表的结构。
g_slist_foreach()对链表的每一项调用Gfunc函数。
Gfunc函数是像下面这样定义的:
typedef void (*GFunc)(gpointer data, gpointer user_data);
在g_slist_foreach()中,Gfunc函数会对链表的每一个list->data调用一次,将user_data传递到g_slist_foreach()函
数中。
////////////////////////////////////////////////////////////////////////////////
例如, 有一个字符串链表,而且想建立一个相似的链表,让每一个字符串作一些变换。
下面是相应的代码,使用了前面例子中的efficient_append()函数。
typedef struct _AppendContext AppendContext;
struct _AppendContext {
GSList* list;
GSList* list_end;
const gchar* append;
} ;
static void append_foreach(gpointer data, gpointer user_data)
{
AppendContext* ac = (AppendContext*) user_data;
gchar* oldstring = (gchar*) data;
efficient_append(&ac->list, &ac->list_end, g_strconcat(oldstring, ac->append, NULL));
}
GSList * copy_with_append(GSList* list_of_strings, const gchar* append)
{
AppendContext ac;
ac.list = NULL;
ac.list_end = NULL;
ac.append = append;
g_slist_foreach(list_of_strings, append_foreach, &ac);
return ac.list;
}
函数列表:访问链表中的数据
#include <glib.h>
GSList* g_slist_find(GSList* list,gpointer data)
GSList* g_slist_nth(GSList* list,guint n)
gpointer g_slist_nth_data(GSList* list,guint n)
GSList* g_slist_last(GSList* list)
gint g_slist_index(GSList* list,gpointer data)
void g_slist_foreach(GSList* list,GFunc func,gpointer user_data)
函数列表: 操纵链表
#include <glib.h>
/* 返回链表的长度* /
guint g_slist_length(GSList* list)
/* 将list1和list2两个链表链接成一个新链表* /
GSList* g_slist_concat(GSList* list1,GSList* list2)
/ *将链表的元素颠倒次序* /
GSList* g_slist_reverse(GSList* list)
/ *返回链表list的一个拷贝* /
GSList* g_slist_copy(GSList* list)
还有一些用于对链表排序的函数,见下面的函数列表。要使用这些函数,必须写一个比较函数GcompareFunc,就像标准
C里面的qsort()函数同样。
在glib里面,比较函数是这个样子:
typedef gint (*GCompareFunc) (gconstpointer a, gconstpointer b);
若是a < b,函数应该返回一个负值;若是a > b,返回一个正值;若是a = b,返回0。
函数列表: 对链表排序
#include <glib.h>
GSList* g_slist_insert_sorted(GSList* list,gpointer data,GCompareFunc func)
GSList* g_slist_sort(GSList* list,GCompareFunc func)
GSList* g_slist_find_custom(GSList* list,gpointer data,GCompareFunc func)
树~~~~~~~~~~~~~~
在glib中有两种不一样的树:GTree是基本的平衡二叉树,它将存储按键值排序成对键值; GNode存储任意的树结构数据
,好比分析树或分类树。
函数列表:建立和销毁平衡二叉树
#include <glib.h>
GTree* g_tree_new(GCompareFunc key_compare_func)
void g_tree_destroy(GTree* tree)
函数列表: 操纵G t r e e数据
#include <glib.h>
void g_tree_insert(GTree* tree,gpointer key,gpointer value)
void g_tree_remove(GTree* tree,gpointer key)
gpointer g_tree_lookup(GTree* tree,gpointer key)
函数列表: 得到G Tr e e的大小
#include <glib.h>
/ *得到树的节点数* /
gint g_tree_nnodes(GTree* tree)
/ *得到树的高度* /
gint g_tree_height(GTree* tree)
使用g_tree_traverse()函数能够遍历整棵树。
要使用它,须要一个GtraverseFunc遍历函数,它用来给g_tree_trave rse()函数传递每一对键值对和数据参数。
只要GTraverseFunc返回FALSE,遍历继续;返回TRUE时,遍历中止。
能够用GTraverseFunc函数按值搜索整棵树。
如下是GTraverseFunc的定义:
typedef gint (*GTraverseFunc)(gpointer key, gpointer value, gpointer data);
G Tr a v e r s e Ty p e是枚举型,它有四种可能的值。下面是它们在G t r e e中各自的意思:
* G_IN_ORDER (中序遍历)首先递归左子树节点(经过GCompareFunc比较后,较小的键),而后对当前节点的键值对调用
遍历函数,最后递归右子树。这种遍历方法是根据使用GCompareFunc函数从最小到最大遍历。
* G_PRE_ORDER (先序遍历)对当前节点的键值对调用遍历函数,而后递归左子树,最后递归右子树。
* G_POST_ORDER (后序遍历)先递归左子树,而后递归右子树,最后对当前节点的键值对调用遍历函数。
* G_LEVEL_ORDER (水平遍历)在GTree中不容许使用,只能用在Gnode中。
函数列表: 遍历GTree
#include <glib.h>
void g_tree_traverse( GTree* tree,
GTraverseFunc traverse_func,
GTraverseType traverse_type,
gpointer data )
一个GNode是一棵N维的树,由双链表(父和子链表)实现。
这样,大多数链表操做函数在Gnode API中都有对等的函数。能够用多种方式遍历。
如下是一个GNode的声明:
typedef struct _GNode GNode;
struct _GNode
{
gpointer data;
GNode *next;
GNode *prev;
GNode *parent;
GNode *children;
} ;
宏列表:访问GNode成员
#include <glib.h>
/ *返回GNode的前一个节点* /
g_node_prev_sibling ( node )
/ *返回GNode的下一个节点* /
g_node_next_sibling ( node )
/ *返回GNode的第一个子节点* /
g_node_first_child( node )
用g_node_new ()函数建立一个新节点。
g_node_new ()建立一个包含数据,而且无子节点、无父节点的Gnode节点。
一般仅用g_node_new ()建立根节点,还有一些宏能够根据须要自动建立新节点。
函数列表: 建立一个GNode
#include <glib.h>
GNode* g_node_new(gpointer data)
函数列表: 建立一棵GNode树
#include <glib.h>
/ *在父节点p a r e n t的p o s i t i o n处插入节点n o d e * /
GNode* g_node_insert(GNode* parent,gint position,GNode* node)
/ *在父节点p a r e n t中的s i b l i n g节点以前插入节点n o d e * /
GNode* g_node_insert_before(GNode* parent,GNode* sibling,GNode* node)
/ *在父节点p a r e n t最前面插入节点n o d e * /
GNode* g_node_prepend(GNode* parent,GNode* node)
宏列表:向Gnode添加、插入数据
#include <glib.h>
g_node_append(parent, node)
g_node_insert_data(parent, position, data)
g_node_insert_data_before(parent, sibling, data)
g_node_prepend_data(parent, data)
g_node_append_data(parent, data)
函数列表: 销毁GNode
#include <glib.h>
void g_node_destroy(GNode* root)
void g_node_unlink(GNode* node)
宏列表:判断G n o d e的类型
#include <glib.h>
G_NODE_IS_ROOT ( node )
G_NODE_IS_LEAF ( node )
下面函数列表中的函数返回Gnode的一些有用信息,包括它的节点数、根节点、深度以及含有特定数据指针的节点。
其中的遍历类型GtraverseType在Gtree中介绍过。
下面是在Gnode中它的可能取值:
* G_IN_ORDER 先递归节点最左边的子树,并访问节点自己,而后递归节点子树的其余部分。
这不是颇有用,由于多数状况用于Gtree中。
* G_PRE_ORDER 访问当前节点,而后递归每个子树。
* G_POST_ORDER 按序递归每一个子树,而后访问当前节点。
* G_LEVEL_ORDER 首先访问节点自己,而后每一个子树,而后子树的子树,而后子树的子树的子树,以次类推。
也就是说,它先访问深度为0的节点,而后是深度为1,而后是深度为2,等等。
GNode的树遍历函数有一个GTraverseFlags参数。这是一个位域,用来改变遍历的种类。
当前仅有三个标志—只访问叶节点,非叶节点,或者全部节点:
* G_TRAVERSE_LEAFS 指仅遍历叶节点。
* G_TRAVERSE_NON_LEAFS 指仅遍历非叶节点。
* G_TRAVERSE_ALL 只是指( G_TRAVERSE_LEAFS | G_TRAVERSE_NON_LEAFS )快捷方式。
函数列表: 取得G N o d e属性
#include <glib.h>
guint g_node_n_nodes(GNode* root,GTraverseFlags flags)
GNode* g_node_get_root(GNode* node)
Gboolean g_node_is_ancestor(GNode* node,GNode* descendant)
Guint g_node_depth(GNode* node)
GNode* g_node_find(GNode* root,GTraverseType order,GTraverseFlags flags,gpointer data)
GNode有两个独有的函数类型定义:
typedef gboolean (*GNodeTraverseFunc) (GNode* node, gpointer data);
typedef void (*GNodeForeachFunc) (GNode* node, gpointer data);
这些函数调用以要访问的节点指针以及用户数据做为参数。GNodeTraverseFunc返回TRUE,中止任何正在进行的遍历,
这样就能将GnodeTraverseFunc与g_node_traverse()结合起来按值搜索树。
函数列表: 访问GNode
#include <glib.h>
/ *对Gnode进行遍历* /
void g_node_traverse( GNode* root,
GTraverseType order,
GTraverseFlags flags,
gint max_depth,
GNodeTraverseFunc func,
gpointer data )
/ *返回GNode的最大高度* /
guint g_node_max_height(GNode* root)
/ *对Gnode的每一个子节点调用一次f u n c函数* /
void g_node_children_foreach( GNode* node,
GTraverseFlags flags,
GNodeForeachFunc func,
gpointer data )
/ *颠倒node的子节点顺序* /
void g_node_reverse_children(GNode* node)
/ *返回节点node的子节点个数* /
guint g_node_n_children(GNode* node)
/ *返回node的第n个子节点* /
GNode* g_node_nth_child(GNode* node,guint n)
/ *返回node的最后一个子节点* /
GNode* g_node_last_child(GNode* node)
/ *在node中查找值为d a t e的节点* /
GNode* g_node_find_child(GNode* node,GTraverseFlags flags,gpointer data)
/ *返回子节点child在node中的位置* /
gint g_node_child_position(GNode* node,GNode* child)
/ *返回数据data在node中的索引号* /
gint g_node_child_index(GNode* node,gpointer data)
/ *以子节点形式返回node的第一个兄弟节点* /
GNode* g_node_first_sibling(GNode* node)
/ *以子节点形式返回node的第一个兄弟节点* /
GNode* g_node_last_sibling(GNode* node)
哈希表~~~~~~~~~~`
GHashTable是一个简单的哈希表实现,提供一个带有连续时间查寻的关联数组。
要使用哈希表,必须提供一个GhashFunc函数,当向它传递一个哈希值时,会返回正整数:
typedef guint (*GHashFunc) (gconstpointer key);
除了GhashFunc,还须要一个GcompareFunc比较函数用来测试关键字是否相等。
不过,虽然GCompareFunc函数原型是同样的,但它在GHashTable中的用法和在GSList、Gtree中的用法不同。
在GHashTable中能够将GcompareFunc看做是等式操做符,若是参数是相等的,则返回TRUE。
函数列表: GHashTable
#include <glib.h>
GHashTable* g_hash_table_new(GHashFunc hash_func,GCompareFunc key_compare_func)
void g_hash_table_destroy(GHashTable* hash_table)
函数列表: 哈希表/比较函数
#include <glib.h>
guint g_int_hash(gconstpointer v)
gint g_int_equal(gconstpointer v1,gconstpointer v2)
guint g_direct_hash(gconstpointer v)
gint g_direct_equal(gconstpointer v1,gconstpointer v2)
guint g_str_hash(gconstpointer v)
gint g_str_equal(gconstpointer v1,gconstpointer v2)
函数列表: 处理GHashTable
#include <glib.h>
void g_hash_table_insert(GHashTable* hash_table,gpointer key,gpointer value)
void g_hash_table_remove(GHashTable * hash_table,gconstpointer key)
gpointer g_hash_table_lookup(GHashTable * hash_table,gconstpointer key)
gboolean g_hash_table_lookup_extended( GHashTable* hash_table,
gconstpointer lookup_key,
gpointer* orig_key,
gpointer* value )
函数列表: 冻结和解冻GHashTable
#include <glib.h>
/ * *冻结哈希表/
void g_hash_table_freeze(GHashTable* hash_table)
/ *将哈希表解冻* /
void g_hash_table_thaw(GHashTable* hash_table)
####################################### GString #####################################
GString的定义:
struct GString
{
gchar *str; /* Points to the st’rsi ncgurrent \0-terminated value. */
gint len; /* Current length */
} ;
用下面的函数建立新的GString变量:
GString *g_string_new( gchar *init );
这个函数建立一个GString,将字符串值init复制到GString中,返回一个指向它的指针。
若是init参数是NULL,建立一个空GString。
void g_string_free( GString *string,gint free_segment );
这个函数释放string所占据的内存。free_segment参数是一个布尔类型变量。
若是free_segment参数是TRUE,它还释放其中的字符数据。
GString *g_string_assign( GString *lval,const gchar *rval );
这个函数将字符从rval复制到lval,销毁lval的原有内容。
注意,若有必要, lval会被加长以容纳字符串的内容。
下面的函数的意义都是显而易见的。其中以_c结尾的函数接受一个字符,而不是字符串。
截取string字符串,生成一个长度为l e n的子串:
GString *g_string_truncate( GString *string,gint len );
将字符串val追加在string后面,返回一个新字符串:
GString *g_string_append( GString *string,gchar *val );
将字符c追加到string后面,返回一个新的字符串:
GString *g_string_append_c( GString *string,gchar c );
将字符串val插入到string前面,生成一个新字符串:
GString *g_string_prepend( GString *string,gchar *val );
将字符c插入到string前面,生成一个新字符串:
GString *g_string_prepend_c( GString *string,gchar c );
将一个格式化的字符串写到string中,相似于标准的sprintf函数:
void g_string_sprintf( GString *string,gchar *fmt,. . . ) ;
将一个格式化字符串追加到string后面,与上一个函数略有不一样:
void g_string_sprintfa ( GString *string,gchar *fmt,... );
################################## 计时器函数 ##################################
建立一个新的计时器:
GTimer *g_timer_new( void );
销毁计时器:
void g_timer_destroy( GTimer *timer );
开始计时:
void g_timer_start( GTimer *timer );
中止计时:
void g_timer_stop( GTimer *timer );
计时从新置零:
void g_timer_reset( GTimer *timer );
获取计时器流逝的时间:
gdouble g_timer_elapsed( GTimer *timer,gulong *microseconds );
################################## 错误处理函数 ##################################
gchar *g_strerror( gint errnum );
返回一条对应于给定错误代码的错误字符串信息,例如“ no such process”等。
使用g_strerror函数:
g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
void g_error( gchar *format, ... );
打印一条错误信息。
格式与printf函数相似,可是它在信息前面添加“ ** ERROR **: ”,而后退出程序。它只用于致命错误。
void g_warning( gchar *format, ... );
与上面的函数相似,在信息前面添加“ ** WARNING **:”,不退出应用程序。它能够用于不太严重的错误。
void g_message( gchar *format, ... );
在字符串前添加“message: ”,用于显示一条信息。
gchar *g_strsignal( gint signum );
打印给定信号号码的Linux系统信号的名称。在通用信号处理函数中颇有用。
################################## 其余实用函数 ##################################
glib还提供了一系列实用函数,能够用于获取程序名称、当前目录、临时目录等。
这些函数都是在glib.h中定义的。
/* 返回应用程序的名称* /
gchar* g_get_prgname (void);
/* 设置应用程序的名称* /
void g_set_prgname (const gchar *prgname);
/* 返回当前用户的名称* /
gchar* g_get_user_name (void);
/* 返回用户的真实名称。该名称来自“passwd”文件。返回当前用户的主目录* /
gchar* g_get_real_name (void);
/* 返回当前使用的临时目录,它按环境变量TMPDIR、TMPandTEMP 的顺序查找。
若是上面的环境变量都没有定义,返回“ / t m p”* /
gchar* g_get_home_dir (void);
gchar* g_get_tmp_dir (void);
/* 返回当前目录。返回的字符串再也不须要时应该用g_free ( ) 释放* /
gchar* g_get_current_dir (void);
/ *得到文件名的不带任何前导目录部分的名称。它返回一个指向给定文件名字符串的指针* /
gchar* g_basename (const gchar *file_name);
/* 返回文件名的目录部分。若是文件名不包含目录部分,返回“ .”。
* 返回的字符串再也不使用时应该用g_free() 函数释放* /
gchar* g_dirname (const gchar *file_name);
/* 若是给定的file_name是绝对文件名(包含从根目录开始的完整路径,好比/usr/local),返回TRUE * /
gboolean g_path_is_absolute (const gchar *file_name);
/* 返回一个指向文件名的根部标志(“/”)以后部分的指针。
* 若是文件名file_name不是一个绝对路径,返回NULL * /
gchar* g_path_skip_root (gchar *file_name);
/ *指定一个在正常程序终止时要执行的函数* /
void g_atexit (GVoidFunc func);
上面介绍的只是glib库中的一小部分, glib的特性远远不止这些。
若是想了解其余内容,参考glib.h文件。这里面的绝大多数函数都是简明易懂的。
另外,http://www.gtk.org上的glib文档也是极好的资源。
若是你须要一些通用的函数,但glib中尚未,考虑写一个glib风格的例程,将它贡献到glib库中!
你本身,以及全世界的glib使用者,都将由于你的出色工做而受益。
glib提供许多有用的函数及定义. 我把它们列在这里并作简短的解释. 不少都是与libc重复, 对这些我再也不详述. 这些大体上是用来参考, 您知道有什麽东西能够用就好.
17.1 定义
为保持资料型态的一致, 这里有一些定义:
G_MINFLOAT
G_MAXFLOAT
G_MINDOUBLE
G_MAXDOUBLE
G_MINSHORT
G_MAXSHORT
G_MININT
G_MAXINT
G_MINLONG
G_MAXLONG
此外, 如下的typedefs. 没有列出来的是会变的, 要看是在那一种平台上. 若是您想要具备可移植性, 记得避免去使用sizeof(pointer). 例如, 一个指标在Alpha上是8 bytes, 但在Inter上为4 bytes.
char gchar;
short gshort;
long glong;
int gint;
char gboolean;
unsigned char guchar;
unsigned short gushort;
unsigned long gulong;
unsigned int guint;
float gfloat;
double gdouble;
long double gldouble;
void* gpointer;
gint8
guint8
gint16
guint16
gint32
guint32
17.2 双向链结串列
如下函数用来产生, 管理及销毁双向链结串列.
GList* g_list_alloc (void);
void g_list_free (GList *list);
void g_list_free_1 (GList *list);
GList* g_list_append (GList *list,
gpointer data);
GList* g_list_prepend (GList *list,
gpointer data);
GList* g_list_insert (GList *list,
gpointer data,
gint position);
GList* g_list_remove (GList *list,
gpointer data);
GList* g_list_remove_link (GList *list,
GList *link);
GList* g_list_reverse (GList *list);
GList* g_list_nth (GList *list,
gint n);
GList* g_list_find (GList *list,
gpointer data);
GList* g_list_last (GList *list);
GList* g_list_first (GList *list);
gint g_list_length (GList *list);
void g_list_foreach (GList *list,
GFunc func,
gpointer user_data);
17.3 单向链结串列
如下函数是用来管理单向链结串列:
GSList* g_slist_alloc (void);
void g_slist_free (GSList *list);
void g_slist_free_1 (GSList *list);
GSList* g_slist_append (GSList *list,
gpointer data);
GSList* g_slist_prepend (GSList *list,
gpointer data);
GSList* g_slist_insert (GSList *list,
gpointer data,
gint position);
GSList* g_slist_remove (GSList *list,
gpointer data);
GSList* g_slist_remove_link (GSList *list,
GSList *link);
GSList* g_slist_reverse (GSList *list);
GSList* g_slist_nth (GSList *list,
gint n);
GSList* g_slist_find (GSList *list,
gpointer data);
GSList* g_slist_last (GSList *list);
gint g_slist_length (GSList *list);
void g_slist_foreach (GSList *list,
GFunc func,
gpointer user_data);
17.4 记忆体管理
gpointer g_malloc (gulong size);
这是替代malloc()用的. 你不须要去检查返回值, 由于它已经帮你作好了, 保证.
gpointer g_malloc0 (gulong size);
同样, 不过会在返回以前将记忆体归零.
gpointer g_realloc (gpointer mem,
gulong size);
重定记忆体大小.
void g_free (gpointer mem);
void g_mem_profile (void);
将记忆体的使用情况写到一个档案, 不过您必需要在glib/gmem.c里面, 加#define MEM_PROFILE, 然後从新编译.
void g_mem_check (gpointer mem);
检查记忆体位置是否有效. 您必需要在glib/gmem.c上加#define MEM_CHECK, 然後从新编译.
17.5 Timers
Timer函数..
GTimer* g_timer_new (void);
void g_timer_destroy (GTimer *timer);
void g_timer_start (GTimer *timer);
void g_timer_stop (GTimer *timer);
void g_timer_reset (GTimer *timer);
gdouble g_timer_elapsed (GTimer *timer,
gulong *microseconds);
17.6 字串处理
GString* g_string_new (gchar *init);
void g_string_free (GString *string,
gint free_segment);
GString* g_string_assign (GString *lval,
gchar *rval);
GString* g_string_truncate (GString *string,
gint len);
GString* g_string_append (GString *string,
gchar *val);
GString* g_string_append_c (GString *string,
gchar c);
GString* g_string_prepend (GString *string,
gchar *val);
GString* g_string_prepend_c (GString *string,
gchar c);
void g_string_sprintf (GString *string,
gchar *fmt,
...);
void g_string_sprintfa (GString *string,
gchar *fmt,
...);
17.7 工具及除错函数
gchar* g_strdup (const gchar *str);
gchar* g_strerror (gint errnum);
我建议您使用这个来作全部错误讯息. 这玩意好多了. 它比perror()来的具备可移植性. 输出为如下形式:
program name:function that failed:file or further description:strerror
这里是"hello world"用到的一些函数:
g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
void g_error (gchar *format, ...);
显示错误讯息, 其格式与printf同样, 但会加个"** ERROR **: ", 然後离开程式. 只在严重错误时使用.
void g_warning (gchar *format, ...);
跟上面同样, 但加个"** WARNING **: ", 不离开程式.
void g_message (gchar *format, ...);
加个"message: ".
void g_print (gchar *format, ...);
printf()的替代品.
最後一个:
gchar* g_strsignal (gint signum);
列印Unix系统的信号名称, 在信号处理时颇有用.
这些大都从glib.h中而来.
使用GLib2.0编写的应用程序,在编译时应该在编译命令中加入`pkg-config -cflags -libs glib-2.0`,如编译一个名为hello.c的程序,输出名为hello的可执行文件,则命令为:
gcc `pkg-config -cflags -libs glib-2.0` hello.c -o hello |
在GLIB中将线程(gthread),插件(gmoudle)和对象系统(gobject)这三个子系统区别对待,编译时要注意加入相应的参数。
如程序中用到对象系统,编译时就应加入:
`pkg-config --cflags --libs gobject-2.0` |
用到线程,编译时则加入:
`pkg-config --cflags --libs gthread-2.0` |
用到插件,编译时则加入:
`pkg-config --cflags --libs gmoudle-2.0` |