浅析GLib

14291 ワード

GLibはGTK+とGNOMEエンジニアリングの基礎の底層のコアライブラリで、1つの総合的な用途の実用的な軽量級のCライブラリで、それはC言語のよく使うデータ構造の定義、関連する処理関数を提供して、面白くて実用的なマクロ、移植可能なパッケージといくつかの実行タイミングエネルギー、例えばイベントループ、スレッド、動的呼び出し、オブジェクトシステムなどのAPI.クラスUNIXのオペレーティングシステムプラットフォーム(LINUX、HP-UNIXなど)、WINDOWS、OS 2、BeOSなどのオペレーティングシステムのプラットフォームで動作することができます.
GLibはスレッドをサポートするオペレーティングシステムと文字セット間変換関数iconvのサポートが必要であり、実際には現代のオペレーティングシステムの多くは以上の2つの機能を持っている.GLibは、ベースタイプ、コアアプリケーションのサポート、実用機能、データ型、オブジェクトシステムの5つの部分から構成されています.GLibの最新バージョンはGLib 2である.2.1,www.gtk.orgサイトはソースコードをダウンロードします.GLib 2を使用する.0作成されたアプリケーションは、helloという名前のコンパイルコマンドにpkg-config -cflags -libs glib-2.0を加えるべきである.cのプログラムは、helloという実行可能ファイルを出力すると、gcc pkg-config -cflags -libs glib-2.0 hello.c-o helloはGLIBでスレッド(gthread)、プラグイン(gmoudle)、オブジェクトシステム(gobject)の3つのサブシステムを区別し、コンパイル時に対応するパラメータを加えることに注意します.プログラムでオブジェクトシステムを使用する場合は、コンパイル時に:pkg-config --cflags --libs gobject-2.0をスレッドに使用し、コンパイル時に:pkg-config --cflags --libs gthread-2.0をプラグインに使用し、コンパイル時に:pkg-config --cflags --libs gmoudle-2.0を追加します.
ベース・タイプ
GLibのベースは、ベースタイプ、範囲限定マクロ、標準マクロ、タイプ変換マクロ、バイト順変換マクロ、数学定数定義、その他のマクロなどからなる.ここでは、GTK+、GNOME、MONOなどの大きなオープンソースプロジェクトのようなGLIBに関連するさまざまなライブラリやパッケージにわたる基礎タイプについて説明します.基礎タイプは標準タイプとも呼ばれ、GLibはC言語のデータ型を統一的に独自のデータ型にカプセル化し、gpointerはポインタタイプ(void*)、guintは符号なし整数(unsigned int)など、gint、gcharなどの修飾性があり、C言語のint、charと全く同じである.これらのデータ型はC言語のデータ型と全く同じように使用されており、熟知していると、より柔軟で直感的で理解しやすいことがわかります.もちろん、C言語のデータ型を直接使用することができます.これはプログラムのコンパイルに少しも影響しません.また、範囲限定マクロやタイプ変換マクロもG_MAXINTは最大のint型値を表し、マクロGINT_TO_POINTER(i)整数変数iをポインタ型、マクロGPOINTER_に変換TO_INT(p)はポインタ型変数pを整数型に変換する.論理タイプgbooleanの値TRUEとFALSEは定数マクロで定義され、G_Eは自然対数を表し、G_PIは円周率を表し、G_PI_2は円周率の1/2などの数学定数を表す.
コアアプリケーションのサポート
GLibのコアアプリケーションのサポートには、イベントループ、メモリ操作、スレッド操作、ダイナミックリンクライブラリの操作、エラー処理、ログなどが含まれます.次のコードでは、イベントループ、メモリ操作、スレッドの3つの機能の簡単な応用を示します.
#include 
static GMutex *mutex = NULL;
static gboolean t1_end = FALSE;
static gboolean t2_end = FALSE;
typedef struct _Arg Arg;
struct _Arg
{
    GMainLoop* loop;
    gint max;
};
void    run_1(Arg *arg)
{
    int i ;

    for(i=0; imax; i++)
    {
        if(g_mutex_trylock(mutex) == FALSE)
        {
            //g_print("%d : thread 2 locked the mutex 
", i);
g_print("%d : 2
"
, i); g_mutex_unlock(mutex); } else { g_usleep(10); } } t1_end = TRUE; } void run_2(Arg *arg) { int i; for(i=0; imax; i++) { if(g_mutex_trylock(mutex) == FALSE) { //g_print("%d : thread 1 locked mutex
", i);
g_print("%d : 1
"
, i); g_mutex_unlock(mutex); } else { g_usleep(10); } } t2_end = TRUE; } void run_3(Arg *arg) { for(;;) { if(t1_end && t2_end) { g_main_loop_quit(arg->loop); break; } } } int main(int argc, char *argv[]) { GMainLoop *mloop; Arg *arg; if(!g_thread_supported()) g_thread_init(NULL); mloop = g_main_loop_new(NULL, FALSE); arg = g_new(Arg, 1); arg->loop = mloop; arg->max = 11; mutex = g_mutex_new(); g_thread_create(run_1, arg, TRUE, NULL); g_thread_create(run_2, arg, TRUE, NULL); g_thread_create(run_3, arg, TRUE, NULL); g_main_loop_run(mloop); g_print(" 3
"
); g_mutex_free(mutex); g_print("
"
); g_free(arg); g_print("
"
); }

Makefileファイルは、CC=gcc all:$(CC)pkg-config --cflags --libs glib-2.0 gthread-2.0 loop.c-o loop出力結果:0:スレッド1反発対象をロックした1:スレッド2反発対象をロックした2:スレッド1反発対象をロックした3:スレッド2反発対象をロックした4:スレッド1反発対象をロックした5:スレッド2反発対象をロックした6:スレッド1反発対象をロックした7:スレッド2反発対象をロックした8:スレッド1反発対をロックした象9:スレッド2反発オブジェクトをロック10:スレッド1反発オブジェクトをロック3イベントループを終了反発オブジェクト解放パラメータを解放するために使用されるメモリ以上のルーチンはrun_1とrun_2操作反発オブジェクト、run_3最初の2つのスレッドが終了したかどうかを検索し、終了したらg_を実行するmain_loop_quitはイベントループを終了します.スレッドの実行は不確定であるため,必ずしも毎回この出力結果であるとは限らない.まず、作成したイベントループのオブジェクトポインタとスレッド実行時の最大ループ数を保存する構造タイプを定義します.一般的に、このデータ構造にメモリを割り当てる場合は、Arg arg=(Arg)malloc(sizeof(Arg));リリース時にfree(arg);このような伝統的なやり方はかつて多くのC言語の初心者に頭を痛めさせ、特に何度も操作する必要がある場合、GLibには類似の関数g_が提供されている.mallocとg_free、最も良い方法はg_をmalloc関数はマクロg_にカプセル化されたnew,このマクロには2つのパラメータがあり,1つ目は構造タイプ,2つ目は構造を割り当てる数であり,このコードでは1つのArgデータ構造しか使用されていないのでg_new(Arg, 1).プログラム終了時にg_freeが解放する.スレッド初期化時には、まず、スレッドが初期化されたか否かを判断する関数g_thread_supportedは、FALSEを返すとスレッドが初期化されていないことを示し、g_を使用する必要があります.thread_Initを初期化するのは賢明な方法です.イベントループGMainLoopはg_main_loop_new作成後すぐには実行されず、g_main_loop_run運転後、g_も使用main_loop_quitは終了します.そうしないと、ループはずっと実行されます.この2つの関数のパラメータはGMainLoop型のポインタで、主関数ではg_を直接実行しません.main_loop_quitではなく、スレッドの関数に入れているので、読者の注意が必要です.
ユーティリティ機能
GLibには20種類近くの実用的な機能が含まれており、簡単な文字処理から初心者には理解しにくいXML解析機能まで、ここではランダム数とタイミングの2つの簡単な機能を紹介します.次のコードは、1~100の間のランダムな整数を生成する方法と、計算時に300000回の累積時間を計算する方法を示します.
/* until.c          */
#include 
int main(int argc, char *argv[])
{
    GRand *rand;
    GTimer *timer;

    gint n;
    gint i, j;
    gint x = 0;
    rand = g_rand_new();    //       
    for(n=0; n<20; n++)
    {   //          
        g_print("%d\t",g_rand_int_range(rand,1,100));
    }
    g_print("
"
); g_rand_free(rand); // // timer = g_timer_new(); g_timer_start(timer);// for(i=0; i<10000; i++) for(j=0; j<3000; j++) x++;// g_timer_stop(timer);// // g_print("%ld\tall:%.2f seconds was used!
"
,x,g_timer_elapsed(timer,NULL)); }

Makefileファイルの内容は、CC=gcc all:$(CC)pkg-config --cflags --libs glib-2.0 until.c-o until出力結果:48 95 95 99 90 24 90 29 78 4 53 87 1 86 7 93 57 8875 4 3000000 all:1.47 seconds was used!GLIBの各オブジェクトには、ほとんど1つ以上の*_があります.new関数を作成するには、タイマGTimerとランダムGRandも同様に、GTimerのg_のようなオブジェクトの使用を終了するために対応する関数があります.timer_stopとGRandのg_rand_free. これはGLIB実用機能の中で最も簡単な2つかもしれませんが、多くの友达は一目瞭然です.また、GLIBのコードスタイルとパッケージテクニックはユニークであることにも注意しなければならない.このスタイルとテクニックは、簡潔で実用的なSDKを自称する汗をかくのに十分であり、このスタイルを学ぶことは私たちに大きな利益をもたらす可能性がある.
データ型
GLibでは、文字列タイプに関する簡単な例として、一般的なデータ構造タイプと関連する操作関数が十数種類定義されています.
#include 
int main(int argc, char *argv[])
{
    GString *s;
    s = g_string_new("Hello");
    g_print("%s
"
, s->str); s = g_string_append(s," World!"); g_print("%s
"
,s->str); s = g_string_erase(s,0,6); g_print("%s
"
,s->str); s = g_string_prepend(s,"Also a "); g_print("%s
"
,s->str); s = g_string_insert(s,6," Nice"); g_print("%s
"
,s->str); } Makefile : CC = gcc all: $(CC) `pkg-config --cflags --libs glib-2.0 ` string.c -o str : Hello Hello World! World! Also a World! Also a Nice World!

文字列はプログラミングにおいて出現頻度が高く,初心者でもよく知られており,追加,削除,挿入などの常用操作を理解すると,他のより複雑な操作をさらに理解することができる.GLibはメモリブロック(GMemChunk)データ型を提供し、割り当てなどの大きなメモリ領域に非常に使いやすい操作方法を提供し、以下のプログラムでメモリブロックデータ型の簡単な使い方を示した.
#include 
int main(int argc, char *argv[])
{
    GMemChunk *chunk;   //     
    gchar *mem[10]; //           
    gint i, j;
    //     
    chunk = g_mem_chunk_new("Test MemChunk", 5, 50, G_ALLOC_AND_FREE);
                //  ,     ,       ,  
    for(i=0; i<10; i++)
    {
        //    
        //mem[i] = g_chunk_new(gchar, chunk);
        mem[i] = (gchar*)g_mem_chunk_alloc(chunk);
        for(j=0; j<5; j++)
        {
            mem[i][j] = 'A' + j;//          
        }
    }

    g_mem_chunk_print(chunk);   //       
    for(i=0; i<10; i++)
    {
        g_print("%s\t",mem[i]);//         
    }

    for(i=0; i<10; i++)
    {
        g_mem_chunk_free(chunk,mem[i]); //         
    }
    g_mem_chunk_destroy(chunk);
}
Makefile     :
CC = gcc
all:
    $(CC) `pkg-config --cflags --libs glib-2.0` data1.c -o data1
       :
GLib-INFO: Test MemChunk: 80 bytes using 2 mem areas
ABCDE   ABCDE   ABCDE   ABCDE   ABCDE   ABCDE   ABCDE   ABCDE   ABCDE   ABCDE

ここで、このデータ型を説明する理由は、メモリ割り当てというランタイム処理の一環の応用の妙を細かく理解できるからです.プログラムには50バイトの空間が割り当てられ,実際には80バイトが用いられていることから,メモリの割り当て自体にメモリ空間の一部が用いられていることがわかる.上記の例のコードから分かるように、GLibのほとんどのオブジェクトはC言語の構造タイプであり、一般的に大文字Gで始まる単語、例えばGListが双方向チェーンテーブルを表すように命名され、それに関連するすべての操作関数は、g_list_*先頭の関数はすべてこれに関連する操作関数であり、これらの関数の最初のパラメータの多くはこのオブジェクトのポインタです.GLIBのデータ型はGLIB自体、特にGTK+で頻繁に使用されており、これらのデータ型の使い方を把握することは非常に必要であり、これはGTK+プログラムのさらなる柔軟な開発にとって重要な一環であり、大学の「データ構造」科に対する良い回顧である.次のGOBJECTオブジェクトシステムでは、GLIBの最も重要な構成部分であるGOBJECTシステムについて詳しく紹介します.C言語で構成された単一継承オブジェクトシステムがGTK+の世界に入るのに役立つことを願っています.