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` |