410 likes | 521 Vues
Multiplatformní nástavba standardní C knihovny (běží na Windows, Linux, Mac, ...)
E N D
Multiplatformní nástavba standardní C knihovny (běží na Windows, Linux, Mac, ...) Naleznete zde nástroje pro komfortní práci s řetězci a poli proměnné velikosti, práci se seznamy, stromy, hashovacími tabulkami či poměrně komplikovanými metodami jako je použití vláken (threads), run-time zavádění modulů (plug-inů) a tak dále... Nahrazuje některé funkce C knihovny a garantuje jejich existenci Každý zdrojový soubor využívající funkce knihovny GLib- musí mít na začátku hlavičkový soubor:#include <glib.h>-musí být nalinkován ke GLib knihovně, zjednodušeně (linux – spustitelný soubor):gcc `glib-config –cflags` `glib-config –libs` test.c -o test Knihovna GLib
GLib definuje svoje datové typy odpovídající standardním C typům + některé vlastní. GLib definuje Boolean:gboolean – může nabývat hodnotTRUEneboFALSE Vše co pochází z GLib knihovny začíná písmenem G, tento zvyk se dodržuje a u jiných knihoven se většinou setkáme s podobnou vlastností. GLib – Základní datové typy
Pro práci s dynamickou pamětí najdeme v Glib ekvivalenty funkcí malloc() a free() + jejich rozšířené verze v podobě maker: g_new(type, count);Toto makro alokuje paměť pro count prvků typu type. Vrácený pointer je přetypován na pointer na daný typ. Jestliže je count rovno 0, vrátí NULL.Př:int *a = g_new(int, 10); /* alokuje 10 * sizeof(int) */ g_new0(type, count);Jako předchozí, navíc nastavý alokovanou paměť na samé nuly. gpointer g_malloc(gulongsize);je obdobou předchozích maker. g_malloc() alokuje size bajtů paměti a vrátí pointer na ni. Je-li size rovno 0, vrátí NULL. gpointer g_malloc0(gulongsize);alokuje size bajtů paměti, které následně všechny nastaví na hodnotu 0. Vrátí pointer na alokovanou paměť. V případě, že size je 0, vrátí NULL. Alokovanou paměť je občas třeba realokovat, a ktomu nám slouží tyto dvě makra:g_renew(type, mem, count);realokuje paměť, na kterou ukazuje pointer mem tak, že nyní je v ní místo pro count prvků typu type. Makro vrátí novou adresu, na které se teď proměnná nachází.gpointer g_realloc(gpointermem, gulongsize);tato funkce realokuje paměť reprezentovanou pointerem mem na velikost size bajtů. Vrátí novou adresu paměti, protože je pravděpodobné, že se při této operaci změní. GLib – práce s pamětí
Každá alokovaná paměť musí být uvolněna a k tomu máme jen jednu funkci:void g_free(gpointermem);která uvolní místo, na které ukazuje pointer mem. Takže GLib definuje svoje funkce pro alokaci paměti a pokud náš program úplně stavíme na GLib, tak bysme měli použít tyto funkce, ale nezapomeňme, že to jsou pouze makra, které volají nám již známé funkce malloc(),free() a realloc(). Glib navíc garantuje funkci, kterou ve standardní C knihovně nenajdeme:gpointer g_memdup(gconstpointermem, guintbyte_size);alokuje byte_size bajtů a zkopíruje do nich byte_size bajtů z mem. Je-li mem rovno NULL, jednoduše vrátí NULL. Jinak vrátí pointer na nově alokovanou oblast paměti. Všechny funkce knihovny GLib při alokaci paměti testují úspěšnost operace. V případě neúspěchu aplikace okamžitě končí. Znamená to tedy, že není třeba testovat, zda-li bylo volání funkce úspěšné a paměť se správně alokovala.příklad:unsigned char *a = g_new(unsigned char, (1024*768) << 2);if (!a) {!!!TADY SE APLIKACE NIKDY NEDOSTANE!!!} GLib – práce s pamětí
gchar* g_basename(const gchar *file_name)vrátí jméno souboru bez předcházející adresářové složky. Vrácený řetězcový pointer ukazuje přímo doprostřed argumentu file_name gchar* g_dirname(const gchar *file_name);vrátí adresářovou složku jména souboru file_name. Pokud file_name neobsahuje cestu i s adresáři, použije se jako návratová hodnota řetězec ".". Vrácená hodnota by měla být po použití dealokována gboolean g_path_is_absolute(const gchar *file_name);vrátí TRUE, jestliže je jméno souboru file_name absolutní, tj. rozhodne, jestli obsahuje plnou cestu z kořenového adresáře. (Např. "/usr/local" v Unixech nebo "C:\WINDOWS\SYSTEM" ve Windows.) gchar* g_path_skip_root(gchar *file_name);vrátí pointer na jméno souboru file_name těsně za označením kořenového adresáře, tj. za lomítkem (/) v Unixech a za C:\ ve Windows. Jestliže file_name není absolutní jméno souboru, funkce předá NULL. gchar* g_get_home_dir(void); gchar* g_get_tmp_dir(void); gchar* g_get_current_dir(void);Funkce hledají zmíněné informace v proměnných prostředí HOME (ve Windows NT i HOMEDRIVE a HOMEPATH), TMPDIR, TMP, TEMP.. GLib – práce s cestami k souborům
Pro ještě větší přenositelnost kódu GLib definuje oddělovače adresářů a cest, jsou to konstantní makra: #define G_DIR_SEPARATOR #define G_DIR_SEPARATOR_SG_DIR_SEPARATOR je na Unixech roven '/' a ve Windows '\'. V makruG_DIR_SEPARATOR_S je definováno totéž, ale jako řetězec (tedy "/" a "\"). #define G_SEARCHPATH_SEPARATOR #define G_SEARCHPATH_SEPARATOR_SG_SEARCHPATH_SEPARATORuchovává oddělovač cest v proměnné prostředíPATH. V Unixu je to dvojtečka (':') a ve Windows středník (';'). Potřebujete-li oddělovač cest zapsaný jako řetězec, sáhněte poG_SEARCHPATH_SEPARATOR_S. GLib – práce s cestami k souborům
Pole (arrays) knihovny GLib jsou podobné polím ze standardního jazyka C. Jejich předností však je, že se automaticky zvětšují s tím, jak do nich přidáváte nové prvky. Přístup k těmto polím je velice podobný přístupu k automaticky rostoucím řetězcůmGString - vždyť také mají mnoho společného. "Nafukovací" pole knihovny GLib jsou definovány strukturou GArray:struct GArray {gchar *data;guintlen;}Prvek data je pointer na informace uložené v poli a můžete k němu přistupovat jako ke standardnímu céčkovskému poli. Jak se však bude pole zvětšovat, bude se měnit. GArray* g_array_new(gbooleanzero_terminated,gbooleanclear,guintelement_size);Argument zero_terminated nastavte na TRUE, chcete-li, aby pole mělo vždy na svém konci vynulovaný prvek (aby bylo ukončeno nulovým ('0') prvkem). Jinak použijte hodnotu FALSE.Chcete-li, aby byly všechny nově alokované položky vynulovány zvolte jako argument clear hodnotu TRUEFunkce vrátí pointer na nově alokovaný GArray, který musí být zrušen voláním g_array_free(). GLib – pole (arrays)
void g_array_free(GArray *array, gbooleanfree_segment);Je-lifree_segmentnastavennaTRUE, uvolní se také data udržované polemarray. Je-li naopak free_segmentroven FALSE, můžete data i nadále používat jako obyčejné céčkovské pole (Nesmíte však zapomenout je nakonec uvolnit volánímg_free()!). #define g_array_append_val(array, v)vytvoří na konci polearraynový prvek a zkopíruje do něj hodnotuv. GArray svou velikost podle potřeby zvětší. Makro vrátí hodnotu argumentuarray.g_array_append_val() je ve skutečnosti makro, kterým voláte funkci g_array_append_vals(). Používá se v něm reference na v, což znamená, že v MUSÍ být proměnná (a ne konstanta, jako např. "96"). GArray* g_array_append_vals(GArray *array,gconstpointerdata, guintlen);Tato funkce vloží len prvků pole data na konec dynamického pole array. data je tedy pointer na první položku, která se má do pole přidat a len je počet těchto položek. GArray array se podle potřeby automaticky zvětší. #define g_array_prepend_val(array, v) GArray* g_array_prepend_vals(GArray *array,gconstpointerdata, guintlen);makro a funkce, které dělají totéž co makrog_array_append_val()a funkceg_array_append_vals() s tím rozdílem, že položky nepřidávají na konec, ale na začátek pole array. GLib – pole (arrays)
#define g_array_insert_val(array, index, data) GArray* g_array_insert_vals(GArray *array, guintindex,gconstpointerdata, guintlen);Makro a funkce, které se postarají o vloženílenprvků z adresy data na index-tou pozici v dynamickém poliarray.data je tedy pointer na první vkládaný prvek, len je počet prvků (v případě použití makra g_array_insert_val() je len=1) a index je místo v poli array, kam se položky umístí. Prvky pole array za tímto indexem se pochopitelně automaticky posunou, aby udělaly pro nově vkládané položky místo a GArray podle potřeby zvětší svou velikost tak, aby mohl pojmout všechny údaje. GArray* g_array_remove_index(GArray *array, guintindex);Odstraní z dynamického pole arraypoložku s indexem index. Vzniklá mezera se vyplní posunutím zbývajících prvků pole na její místo. Funkce zachovává pořadí prvků. Vrácenou hodnotou je pointer na GArray. Array* g_array_remove_index_fast(GArray *array, guintindex);Jak již název napovídá, půjde o rychlejší variantu funkce na odstranění položky z pole array. Čas na vykonání operace se ušetří tak, že po odstranění položky s indexem index se místo posouvání zbývajících prvků do vzniklé mezery přesune poslední prvek pole. Funkce g_array_remove_index_fast() proběhne o něco rychleji než funkce g_array_remove_index(), její nevýhodou však je, že nezachovává pořadí prvků v poli. To ji tedy předurčuje k použití pouze tam, kde tato vlastnost nevadí (kde nezáleží na pořadí položek v poli a je jedno, jaký index prvky mají). GLib – pole (arrays)
K přístupu k položkám dynamických polí můžete použít makro#define g_array_index(a,t,i) (((t*) (a)->data) [(i)])Toto makro v podstatě zastřešuje a zpřehledňuje práci s položkou data struktury GArray.Malí příklad:/* prirazeni hodnoty 5. polozce pole */g_array_index(array, gint, 5) = 0;/* prace s polozkou number struktury MyStruct, ktera je 7. prvkem pole typedef struct { int number } MyStruct;*/g_array_index(array, MyStruct, 7).number = 12;/* ziskani pointeru na 3. polozku pole typu gfloat */gfloat *p = &(g_array_index(array, gfloat, 3)); GLib – pole (arrays)
Pomocí GArray můžeme vytvožit libovolně rostoucí pole jakéhokoliv typu, ale Glib nabízí pro speciální účely ještě např:GPtrArray – pole pro práci s pointery - gpointerGByteArray – pole pro práci s typem unsigned char (nebo guint8) Funkce těchto dvou polí se nijak neliší, jsou optimalizované a přizpůsobené pro daný typ (gpointer nebo guint8). GByteArray* g_byte_array_new(void); GByteArray* g_byte_array_append(GByteArray *array, const guint8 *data, guintlen); GByteArray* g_byte_array_prepend(GByteArray *array, const guint8 *data, guintlen); GByteArray* g_byte_array_set_size(GByteArray *array, guintlength); GByteArray* g_byte_array_remove_index(GByteArray *array, guintindex); GByteArray* g_byte_array_remove_index_fast(GByteArray *array, guintindex); #define g_byte_array_index(a,i) (((guint8*) (a)->data) [(i)]) void g_byte_array_free(GByteArray *array, gbooleanfree_segment); GPtrArray* g_ptr_array_new(void); void g_ptr_array_add(GPtrArray *array, gpointerdata); void g_ptr_array_set_size(GPtrArray *array, gintlength); gboolean g_ptr_array_remove(GPtrArray *array, gpointerdata); gpointer g_ptr_array_remove_index(GPtrArray *array, guintindex); gboolean g_ptr_array_remove_fast(GPtrArray *array, gpointerdata); gpointer g_ptr_array_remove_index_fast(GPtrArray *array, guintindex); #define g_ptr_array_index(array,index) void g_ptr_array_free(GPtrArray *array, gbooleanfree_seg); GLib – pole (závěr)
Glib nám nabízí funkce pro práci se standardními C řetězci. Definuje některé funkce ekvivalentní knihovně C + některé své. Funkce byly vytvořeny z důvodů bezpečnosti a přenositelnosti. Do všech typů funkce (g_)printf() můžeme vložit formát ve formě pozičních argumentů, malý příklad:char *text = g_strdup_printf(“%2$d, %1$d\n“, 1, 2); printf(text); g_free(text);/* vystup bude: 2, 1 */ Funkce, které vytvoří nový řetězec:gchar* g_strdup(const gchar *str);gchar* g_strndup(const gchar *str, guintn);gchar* g_strnfill(guintlength, gcharfill_char); gchar* g_strdup_printf(const gchar *format, ...);gchar* g_strdup_vprintf(const gchar *format, va_listargs);gint g_snprintf(gchar *string, gulongn, const gchar *format, ...);gint g_vsnprintf(gchar *string, gulongn, const gchar *format, va_listargs);guint g_printf_string_upper_bound(const gchar *format, va_listargs);(vypočítá a vrátí maximální velikost paměti, které je třeba k uložení výstupu) Funkce, které porovnávají řetězce (bez rozlišení velkých a malých písmen):gint g_strcasecmp(const gchar *s1, const gchar *s2);gint g_strncasecmp(const gchar *s1, const gchar *s2, guintn); Různé:void g_strup(gchar *string); převede řetězec na velké písmenavoid g_strdown(gchar *string); převede řetězec na malé písmenavoid g_strreverse(gchar *string); převrátí řetězec (znaky)gdouble g_strtod(constgchar *nptr, gchar **endptr); převede na double GLib – řetězce
Odstraňování bílých znaků: gchar* g_strchug(gchar *string);Odstraní všechny bílé znaky (white spaces) ze začátku řetězce string. Zbývající znaky posune na začátek tak, aby vyplnily vzniklou mezeru. Vrátí string. gchar* g_strchomp(gchar *string);Odstraní všechny bílé znaky (white spaces) z konce řetězce string. Vrátí string. #define g_strstrip(string)Makro, které odstraní všechny bílé znaky (white spaces) ze začátku i konce řetězce. Spojování řetězců dohromady: gchar* g_strconcat(const gchar *string1, ...);Spojí všechny řetězce, zapsané jako argumenty funkce, dohromady. Řetězce zapisujte jako argumenty postupně za sebou v takovém pořadí, v jakém je chcete spojit. Posledním prvkem musí být vždy NULL. Výsledný, nově alokovaný řetězec funkce použije jako návratovou hodnotu. Vrácený řetězec je třeba po použití dealokovat. Vstupní řetězce zůstanou nedotčeny. gchar* g_strjoin(const gchar *separator, ...);Tato funkce spojí všechny řetězce, zadané jako argumenty ..., dohromady. Mezi každé dva vloží volitelný řetězec separator. Je-li separator roven NULL, mezi řetězce se nebude vkládat nic (analogie s funkcí g_strconcat()). Posledním prvkem v seznamu argumentů (řetězců) musí být NULL. Vrácený řetězec je výsledek operace sloučení. Je nově alokovaný v paměti a proto by měl být po použití dealokován. GLib – řetězce
Nahrazení znaků v řetězci: gchar* g_strdelimit(gchar *string, constgchar *delimiters,gcharnew_delimiter);funkce, která nahradí rozdělovací znaky v řetězci string znakem new_delimiter. Každý znak řetězce string, který bude nalezen v řetězci delimiters, bude nahrazen znakem new_delimiter. Je-li delimiters rovno NULL, použijí se rozdělovací znaky def. jako:#define G_STR_DELIMITERS "_-|> <."Změny se provedou přímo v řetězci string. Funkce g_strdelimit() jako návratovou hodnotu použije vstupní argument string. Rozdělování řetězců na pole řetězců: gchar** g_strsplit(const gchar *string,const gchar *delimiter, gintmax_tokens);Tato rutina se postará o alokování pole řetězců, které předá jako návratovou hodnotu. Pole řetězců vytvoří z řetězce string tak, že jej rozdělí na maximálně max_tokens částí v místech specifikovaných řetězcem delimiter.Každý znak řetězce delimiter bude v řetězci string chápán jako místo, kde má dojít k rozdělení. Je-li max_tokens menší než 1, rozdělí se celý řetězec. Je-li však max_tokens kladná nenulová hodnota a počet rozdělení dosáhne tohoto čísla, poslední řetězec ve vráceném poli řetězců bude obsahovat zbytek řetězce string (nezáleží na tom, že třeba ještě obsahuje nějaké rozdělovací znaky z delimiter). K uvolnění pole řetězců vytvořeného funkcí g_strsplit() používejte: void g_strfreev(gchar **str_array); GLib – řetězce
Každý, kdo už někdy pracoval s řetězci v C zjistí, že práce s nimi je někdy dost pracná, hlídat si velikost alokované paměti pro řetězec, realokovat paměť pro vložení, atd...GLib to samozdřejmě řeší strukturou GString. Je to něco jako GArray přispůsobené na řetězec.struct GString {gchar *str;gintlen;}Řetězec str je v tomto případě obyčejný céčkovský řetězec ukončený nulovým znakem ('\0') a takto k němu můžete i přistupovat. Pokud si nejste opravdu jisti tím, co děláte, používejte jej přímým voláním jen ke čtení. K zápisu využijte výhradně funkcí popsaných níže.Položka len vždy obsahuje délku řetězce str bez ukončovacího znaku '\0'.Jelikož se řetězec automaticky realokuje, jak do něj přidáváte text, je velice pravděpodobné, že se bude v paměti stěhovat. Nelze tedy spoléhat na to, že pointer str bude ukazovat vždy na stejné místo v paměti. GLib – řetězce GString
Funkce pro vytvoření a uvolnění struktury GString: GString* g_string_new(const gchar *init);Tato funkce vytvoří nový GString, tedy alokuje místo pro strukturu GString a přiřadí do ní řetězec init. Vrátí pointer na nově vzniklý GString GString* g_string_sized_new(guintdfl_size);Funkce, která vytvoří nový GString s dostatkem místa pro dfl_size znaků. To je užitečné, když do řetězce hodláte mnohokrát přidávat text a nechcete, aby se realokoval příliš často. void g_string_free(GString* string, gintfree_segment);Tato funkce uvolní z paměti GString. Je-li navíc free_segment nastaven na TRUE, dealokují se také textová data udržovaná GStringem (položka str struktury GString - viz. výše). Je-li free_segment FALSE, text zůstane v paměti, takže jej můžete dále používat jako obyčejný řetězec ukončený nulovým znakem. Funkci g_string_sized_new() můžete využít, když chcete například manuálně nastavit řetězec ve struktuře GString. GLib – řetězce GString
Práce s textem: GString* g_string_append(GString *string, const gchar *val);Tato funkce přidá do textového bufferu string řetězec val. GString* g_string_append_c(GString *string, gcharc);Tato funkce přidá jeden znak c do textového bufferu string. GString* g_string_prepend(GString *string, const gchar *val);Funkce, která přidá na začátek textového bufferu string řetězec val. GString* g_string_prepend_c(GString *string, gcharc);Funkce, která přidá jeden znak c na začátek textového bufferu string. GString* g_string_insert(GString *string, gintpos,const gchar *val);Funkce, která vloží do textového bufferu string na pozici pos řetězec val. GString* g_string_insert_c(GString *string, gintpos,gcharc);Funkce, která vloží do textového bufferu string na pozici pos znak c. GString* g_string_assign(GString *lval, constgchar *rval);Funkce, která zkopíruje obsah řetězce rval do textového bufferu lval. Původní obsah GStringu lval se zruší. GLib – řetězce GString
Práce s formátovaným textem: void g_string_sprintf(GString* string,const gchar *format, ...); tato funkce je podobná funkci sprintf() ze standardního céčka, uloží do GStringu formátovaný řetězec daný formátem format a volitelnými parametry funkce. Předcházející obsah je odstraněn. void g_string_sprintfa(GString* string,const gchar *format, ...);Je podobná předchozí funkci. Liší se tím, že formátovaný řetězec daný formátem format přidá na konec textového bufferu string. Znak 'a' na konci jména funkce znamená append. Odstraňování textu: GString* g_string_erase(GString *string, gintpos, gintlen);Tato funkce odstraní len znaků z GStringu string počínaje znakem na pozici pos (první znak má index 0). Zbytek řetězce je posunut dolů tak, aby vyplnil mezeru. GString* g_string_truncate(GString *string, gintlen);Odstraní konec řetězce, uloženého v GStringu string tak, že ponechá jen prvních len znaků. GLib – řetězce GString
Ostatní funkce: GString* g_string_up(GString *string);zkonvertuje veškerý text uložený v GStringu string na velká písmena abecedy. GString* g_string_down(GString *string);zkonvertuje veškerý text uložený v GStringu string na malá písmena abecedy.(nevím jestli tyto funkce používají lokalizaci ze systémové proměnné LOCALE) Malý příklad:int main(void) {GString *s, *t;gchar *u; /* pomocny pointer (retezec) *//* inicializace novych retezcu */s = g_string_new("ahoj"); /* vytvoreni s prirazenim */t = g_string_sized_new(10); /* retezec v t zabira 10 bajtu */ g_string_assign(t, "nazdar"); /* prirazeni */ g_string_up(s); /* konverze na velka pismena *//* kontrolni vypis */ printf("obsah s: %s; delka s: %d\n", s->str, s->len); printf("obsah t: %s; delka t: %d\n", t->str, t->len);u = s->str; /* u nyni ukazuje na retezec ulozeny v s *//* dealokace */ g_string_free(s, FALSE); /* data z s zustavaji v pameti */ g_string_free(t, TRUE); /* dealokuj veskery obsah t *//* kontrolni vypis - data pochazejici z GStringu s existuji! */ printf("obsah u: %s\n", u); g_free(u); /* dealokuj retezec, ktery pochazi z s */ return(0); } GLib – řetězce GString
Hash tabulky (asociativní pole), představují výkonný programátorský nástroj, který realizuje spojení dat s jejich jednoznačným klíčem, takže pokud zadáte klíč, data mohou být v hash tabulce díky výkonným algoritmům velice rychle nalezena.Hash tabulka je v knihovně GLib reprezentována strukturou GHashTable. Všechny položky této struktury jsou neveřejné a doporučuje se k nim přistupovat výhradně použitím speciálních funkcí.Hash tabulka je implementována universálně, takže lze zadat funkci pro porovnávání a funkci pro výpočet hashové hodnoty:guint(*GHashFunc)(gconstpointerkey);gint(*GCompareFunc)(gconstpointera, gconstpointerb); GLib sama o sobě definuje 3 typy hashovacích a porovnávacích funkcí, pomocí těchto funkcí můžeme vytvořit různé hash tabulky na různé účely. Vytvoření hash tabulky: GHashTable* g_hash_table_new(GHashFunchash_func,GCompareFunckey_compare_func);Funkce vrací pointer na nově alokovanou strukturu GHashTable a jako parametry si žádá dvě funkce. První musí odpovídat typu GHashFunc a druhá GcompareFunc. Př: g_hash_table_new(g_str_hash, g_str_equal); Vytvoří HT pro řetězce g_hash_table_new(g_int_hash, g_int_equal); Vytvoří HT pro typ gint GLib – Hash tabulky (GHashTable)
Zničení hash tabulky: void g_hash_table_destroy(GHashTable *hash_table);dealokuje paměť vyhrazenou pro hash tabulku hash_table. Pokud jste do tabulky ukládali dynamická data a klíče, musíte je dealokovat ještě předtím, než provedete tuto funkci. Vkládání dat: void g_hash_table_insert(GHashTable *hash_table, gpointerkey, gpointervalue);Vloží do hash tabulky hash_table klíč key a data value. Jestliže už klíč v tabulce existuje, jeho stávající hodnota je nahrazena novou.Je třeba upozornit, že hodnoty key a value jsou v hash tabulce uchovány tak, jak je funkce g_hash_table_insert() dostane. Neprovádí se žádná kopie apod. Používáte-li pouze statická data, je vše v pořádku, ale s dynamickými daty nastávají potíže. Musíte ručně zajistit, že se dealokují při odstraňování z hash tabulky. Z tohoto důvodu se nedoporučuje do jedné GHashTable ukládat statické a dynamické hodnoty zároveň (ty statické realokujte na dynamické použitím funkce g_strdup()).Vyplývá z toho následující: pokud do GHashTable ukládáte dynamicky alokovaná data, musíte se před operací vkládání přesvědčit, že tam žádná data s klíčem key ještě nejsou. Pokud by byly, musíte ta stará nejprve dealokovat. Doporučuju kouknout se do zdrojáků a zjistit jak je funkce udělaná: soubor glib/ghash.c GLib – Hash tabulky (GHashTable)
Získání dat: gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointerkey);v hash tabulce hash_table vyhledá záznam s klíčem key a vrátí pointer na jeho data nebo NULL, nebyl-li takový klíč nalezen. gboolean g_hash_table_lookup_extended(GHashTable *hash_table, gconstpointerlookup_key, gpointer *orig_key, gpointer *value);tato funkce vyhledá v tabulce hash_table záznam odpovídající klíči lookup_key a do proměnných orig_key a value uloží původní klíč a jemu přiřazená data. Funkce vrátí TRUE, byl-li klíč v tabulce nalezen nebo FALSE v opačném případě. Tato funkce je užitečná, když potřebujete dealokovat originální klíč, třeba před voláním g_hash_table_remove() (viz později). Odstranění dat: void g_hash_table_remove(GHashTable *hash_table, gconstpointerkey);odstraní klíč key a jemu asociovaná data. Pokud hash tabulka uchovává dynamicky alokovaná data, musíte se postarat o jejich uvolnění z paměti ručně. GLib – Hash tabulky (GHashTable)
Odstranění dat (pokr.) guint g_hash_table_foreach_remove(GHashTable *hash_table,GHRFuncfunc, gpointeruser_data);gboolean(*GHRFunc)(gpointerkey, gpointervalue, gpointeruser_data);Funkce g_hash_table_foreach_remove() slouží k odstranění i několika položek najednou. Na každou dvojici klíč--data tabulky hash_table zavolá uživatelskou funkci func, která musí odpovídat předpisu GHRFunc, a když ona vrátí TRUE, daný záznam bude z hash_table odstraněn.Parametr user_data bude v nezměněné podobě předán volané funkci func.Funkce g_hash_table_foreach_remove() vrací počet odstraněných položek. Další funkce: guint g_hash_table_size(GHashTable *hash_table);Funkce vrátí počet dvojic klíč--data uložených v tabulce hash_table. GLib – Hash tabulky (GHashTable)
Odstranění dat (pokr.) void g_hash_table_foreach(GHashTable *hash_table, GHFuncfunc, gpointeruser_data);void(*GHFunc) (gpointerkey, gpointervalue, gpointeruser_data);Funkce g_hash_table_foreach() zavolá na každý záznam (dvojici klíč--data) tabulky hash_table funkci func, které předá klíč (key), jeho data (value) a uživatelská data (user_data). void g_hash_table_freeze(GHashTable *hash_table); void g_hash_table_thaw(GHashTable *hash_table);Standardně, po každém vložení nebo odebrání prvku z tabulky se provádí vnitřní přeuspořádání položek. Tato operace ukrádá kousek strojového času, takže když hodláte v hash tabulce provést najednou větší množství změn, je vhodné nejprve zavolat funkci g_hash_table_freeze(), která tabulku hash_table zmrazí, takže se po každém přidání či odebrání prvku nebude přebudovávat vnitřní struktura položek. Po dokončení úprav zavolejte g_hash_table_thaw(), přebudovávání obnovíte.Hash tabulky si pamatují, kolikrát byly "zmrazeny" a proto kolikrát zavoláte funkci g_hash_table_freeze(), tolikrát musíte zavolat i g_hash_table_thaw(). GLib – Hash tabulky (GHashTable)
Strom je takové uspořádání prvků (uzlů, nodes), ve kterém lze rozeznat předchůdce (rodiče - parent) a následovníky (děti - children). Každý prvek může mít nejvýše jednoho předchůdce a několik následovníků (binární stromy nejvíce dva). Kořenem (root) nazýváme takový prvek, který nemá předchůdce. V každém stromu se nachází jen jeden kořen. Naopak listy (leafs) jsou takové prvky, které nemají žádného následovníka. Má-li strom jen jeden prvek, je kořenem i listem zároveň - hybrid. Binární stromy knihovny GLib jsou reprezentovány strukturou GTree. Všechny položky této struktury jsou skryté, což znamená, že by se se stromem mělo pracovat jen pomocí vymezené sady funkcí, kterou si v této a následující části popíšeme. Do stromu GTree se ukládají dvojice klíč--data. GTree je neustále vyvažován, takže cesta od kořene k listům je vždy nejmenší možná. To je předpokladem dobré efektivity vyhledávacího algoritmu. Vytvoření a zničení binárního stromu: GTree* g_tree_new(GCompareFunckey_compare_func);Jako jediný parametr se jí předává funkce key_compare_func, která musí odpovídat předpisu: gint (*GCompareFunc) (gconstpointera, gconstpointerb); void g_tree_destroy(GTree *tree);Uvolní binární strom tree z paměti. Pokud jste ale používali dynamicky alokované klíče nebo data, musíte je ještě před voláním g_tree_destroy() dealokovat sami. GLib – Binární stromy
Přidávání prvků: void g_tree_insert(GTree *tree, gpointerkey,gpointervalue);Tato funkce vloží do binárního stromu tree pod klíčem key data value. Jestliže prvek s klíčem key ve stromu již existuje, budou jeho stará data nahrazena novými.Strom je automaticky "vyvážen", takže vzdálenost listů od kořene zůstává co nejmenší. Získávání dat: gpointer g_tree_lookup(GTree *tree, gpointerkey);vyhledá v binárním stromu tree uzel s klíčem key a vrátí jemu přiřazená data. Vyhledání dat podle klíče je velmi rychlé, protože strom je v každém okamžiku "vyvážen" (balanced). Odstraňování prvků: void g_tree_remove(GTree *tree, gpointerkey);ze stromu tree odstraní podle hodnoty klíče key dvojici klíč--data. Pokud jste klíč nebo data alokovali dynamicky, musíte se sami postarat o to, abyste je také dealokovali. Vyhledávání: gpointer g_tree_search(GTree *tree, GSearchFuncsearch_func, gpointerdata);Funkce, která má za úkol vyhledat ve stromu tree danou položku. Vyhledávání se realizuje pomocí funkce search_func. GLib – Binární stromy
Procházení stromem: void g_tree_traverse(GTree *tree, GTraverseFunctraverse_func, GTraverseTypetraverse_type, gpointerdata);gint (*GTraverseFunc)(gpointerkey, gpointervalue, gpointerdata);typedef enum {G_IN_ORDER,G_PRE_ORDER,G_POST_ORDER,G_LEVEL_ORDER/* není pro binární stromy. */} GTraverseType;Procházení stromem tree, funkce traverse_func je zavolána pro každý pár, pořadí určuje traverse_type. Parametr data bude předán nezměněn funkci func. GLib – Binární stromy
#include <glib.h>gint my_compare(gconstpointera, gconstpointerb){ return (strcmp((gchar *) a, (gchar *) b));}gint main(void){GTree *tree;/* inicializace stromu */tree = g_tree_new(my_compare); g_tree_insert(tree, "Karel", GINT_TO_POINTER(100)); g_tree_insert(tree, "Petr", GINT_TO_POINTER(200)); g_tree_insert(tree, "Josef", GINT_TO_POINTER(150)); g_tree_insert(tree, "Adam", GINT_TO_POINTER(620)); g_tree_insert(tree, "Pavel", GINT_TO_POINTER(490));/* ziskani hodnot */ printf("Josef ma %d Kc\n", g_tree_lookup(tree, "Josef"));/* dealokace */ g_tree_destroy(tree);} GLib – Binární stromy - příklad
Seznam (angl. list) jako abstraktní datová struktura je velmi často používaný v oblasti nenumerického zpracování dat. Je tvořen dynamickou posloupností prvků, které jsou navzájem svázány pointery tak, že tvoří pomyslný řetěz položek. V programu pak stačí uchovávat pouze pointer na první prvek seznamu a díky němu se postupně přes jednotlivé pointery můžeme dostat ke každé položce seznamu. struct GList{gpointerdata;GList *next;GList *prev;};Pointer data slouží k uložení ukazatele na data, které chceme v seznamu uchovávat.Položky next a prev jsou pointery na následující popř. předcházející prvek seznamu, můžou se používat při procházení seznamem v obou směrech.U obousměrných seznamů - v kontrastu s tím, na co jsme byli dosud zvyklí - neexistuje funkce pro vytvoření GListu. Prázdný seznam je jednoduše GList* nastavený na NULL. Funkcím, které se seznamy pracují, se obvykle předává pointer na první položku seznamu. GLib – Obousměrné seznamy (GList)
Přidávání položek do obousměrného seznamu: GList* g_list_append(GList *list, gpointerdata); GList* g_list_prepend(GList *list, gpointerdata); GList* g_list_insert(GList *list, gpointerdata,gintposition);GList* g_list_insert_sorted(GList *list, gpointerdata,GCompareFuncfunc);Pro všechny tři platí, že argument list je pointer na první položku seznamu, nebo NULL, vytváříme-li nový seznam. Argument data jsou ukládaná data (buď pointer na datovou položku nebo přetypovaný gint/guint).Funkce g_list_append() přidá prvek data na konec seznamu, g_list_prepend() na začátek seznamu a funkce g_list_insert() vloží položku data na pozici danou argumentem position. Je-li position, argument funkce g_list_insert(), záporná hodnota nebo hodnota větší než počet prvků v seznamu, uloží se nový prvek na konec.Volání g_list_insert() s position rovno 0 je ekvivalentem volání g_list_prepend(), position rovno 1 vytvoří novou položku hned za prvkem list a podobně. první položku seznamu. GLib – Obousměrné seznamy (GList)
Odstrnění položek do obousměrného seznamu: GList* g_list_remove(GList *list, gpointerdata);Tato funkce odstraní z obousměrného seznamu list položku s daty data. Argument list je tedy pointer na první položku seznamu a data pointer na uložená data. Navrácená hodnota je nový počátek seznamu. Jestliže se v seznamu vyskytují dvě položky se stejnými daty, je odstraněna pouze první z nich. Jestliže v seznamu neexistuje položka, která by data obsahovala, zůstane seznam nezměněn.Funkcí g_list_remove() se prvek GList dealokuje. data však zůstanou nedotčena - v případě, že už nejsou potřeba, je nutno je dealokovat zvlášť. GList* g_list_remove_link(GList *list, GList *llink);Ze seznamu, na jehož počátek ukazuje parametr list, odstraní prvek llink, ale nedealokuje ho. Položky prev a next (viz struktura GList) odstraněného prvku llist se nastaví na NULL, takže se z listu vlastně stane samostatný seznam o jednom prvku. Není-li již takto odstraněné položky potřeba, je nutno ji dealokovat voláním funkce g_list_free_1(). Dealokace obousměrných seznamů: void g_list_free(GList *list);dealokuje seznam, kde list je pointer na počátek seznamu. void g_list_free_1(GList *list);Pozor! Není možné libovolnou položku seznamu pouze takto jednoduše dealokovat. Musíme ji nejprve ze seznamu odstranit voláním funkce g_list_remove_link(). GLib – Obousměrné seznamy (GList)
Procházení obousměrným seznamem: GList* g_list_first(GList *list);Vrátí první položku seznamu. list je jeho libovolný prvek. GList* g_list_last(GList *list);Vrátí poslední položku seznamu. list je libovolný prvek.K získání následujícího nebo předcházejícího prvku můžete využívat přímý přístup k položkám next popř. prev struktury GList nebo použít následující makra, která navíc provádějí kontrolu na (nechtěné) předání NULL: GList* g_list_nth(GList *list, guintn);Vrátí n-tý prvek v pořadí od prvku list (list je chápán jako nultý) nebo NULL, není-li v seznamu tolik prvků. Záporné hodnoty n nejsou povoleny. gpointer g_list_nth_data(GList *list, guintn);Vrátí pointer na data n-tého prvku v pořadí od prvku list (list je chápán jako nultý) nebo NULL, není-li v seznamu tolik prvků. Záporné hodnoty n nejsou povoleny. GLib – Obousměrné seznamy (GList)
Prohledávání obousměrného seznamu: gint g_list_position(GList *list, GList *llink); gint g_list_index(GList *list, gpointerdata);Tyto dvě funkce vrací index (pořadí) listu llink od začátku list. První funkce potřebuje k nalezení ukazatel na list, druhé funkce stačí data. GList* g_list_find(GList *list, gpointerdata); GList* g_list_find_custom(GList *list, gpointerdata,GCompareFuncfunc);Obě vracejí pointer na nalezenou položku seznamu, obě požadují jako parametr list počátek tohoto seznamu stejně tak jako pointer na data hledaného prvku. Odlišný však je způsob, jakým položku GList vyhledají.Použitím funkce g_list_find_custom() máte nad vyhledáváním úplnou kontrolu. Jako poslední argument této funkce se předává nám již známá funkce typu GCompareFunc a právě ona rozhoduje o relaci mezi dvěma položkami seznamu a tak potažmo i o tom, který prvek seznamu bude prohlášen za ten pravý. GLib – Obousměrné seznamy (GList)
Další funkce: void g_list_foreach(GList *list, GFuncfunc, gpointeruser_data);Funkce která na každý prvek seznamu list zavolá funkci func a mimo jiné jí předá i data user_data.void (*GFunc)(gpointerdata, gpointeruser_data); guint g_list_length(GList *list);Vrátí počet prvků v obousměrném seznamu. GList* g_list_copy(GList *list);Vytvoří nově alokovanou kopii seznamu list. Pointery na data se do nového seznamu pouze jednoduše kopírují, takže ukazují-li na nějaké dynamické datové položky, budou mít oba seznamy všechny ukazatele na stejná data (jinými slovy, kopie dynamických dat se neprovádí). GList* g_list_reverse(GList *list);Obrátí pořadí prvků v seznamu list a vrátí pointer na nový počátek. (Tzn. první položka bude poslední, druhá bude předposlední atd.) GList* g_list_sort(GList *list, GCompareFunccompare_func);Seřadí seznam list podle kritéria definovaného funkcí compare_func. GList* g_list_concat(GList *list1, GList *list2);Seznam list2 připojí na konec seznamu list1. Pozor: Položky druhého seznamu nejsou duplikovány. GLib – Obousměrné seznamy (GList)
Jednosměrné seznamy jsou těžkou analogií k obousměrným. Základní rozdíl, v čem se tyto dva typy liší, je skutečnost, že jednosměrné seznamy lze procházet jen v jednom směru, tj. nedisponují pointery na "předcházející" prvky (prev). Uzly jednosměrných seznamů jsou definovány strukturou GSList:struct GSList{gpointerdata;GSList *next;}; Funkce pro jednosměrné seznami jsou velmi podobné těm obousměrným, jediné co chybý jsou funkce, které potřebují předcházející prvky. GLib – Jednosměrné seznamy (GSList)
Otázka kódování různých jazyků je velmi složitá, a proto vzniklo univerzální kódování – Unikód (UNICODE). Unikód můžou být 8 16 a 32 bitové řetězce. Protože 16 a 32 bytové řetězce ruší kompatibility se standardními ansi-8 bitovými, vzniklo kódování utf8, toto kódování zachováná prvních 127 znaků z kódování ISO-8859-1 a zbylý bit určuje zda znak nebude zakódován do více bytů. Více na www.unicode.org. Obdoba standardních funkcí definovaných v ctype.h: gboolean g_unichar_isalnum (gunicharc); gboolean g_unichar_isalpha (gunicharc); gboolean g_unichar_iscntrl (gunicharc); gboolean g_unichar_isdigit (gunicharc); gboolean g_unichar_isgraph (gunicharc); gboolean g_unichar_islower (gunicharc); gboolean g_unichar_isprint (gunicharc); gboolean g_unichar_ispunct (gunicharc); gboolean g_unichar_isspace (gunicharc); gboolean g_unichar_isupper (gunicharc); gboolean g_unichar_isxdigit (gunicharc); gboolean g_unichar_istitle (gunicharc); gboolean g_unichar_isdefined (gunicharc); gboolean g_unichar_iswide (gunicharc); gunichar g_unichar_toupper (gunicharc); gunichar g_unichar_tolower (gunicharc); gunichar g_unichar_totitle (gunicharc); GLib – Unikód
Pro zjištění zda je použita utf8 locale je funkce:gboolean g_get_charset(char **charset);Vrací TRUE jestli ano. Převod unicode znaku na číslo: gint g_unichar_digit_value(gunicharc); gint g_unichar_xdigit_value(gunicharc); Nízkoúrovňové funkce pro průchod v řetězcích. #define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(guchar *)(p)])Skok na další unicode znak v řetězci. gchar* g_utf8_prev_char(const gchar *p);Skok na předchozí unicode znak. gunichar g_utf8_get_char(const gchar *p);Dekóduje a vrátí unicode znak v řetězci. gunichar g_utf8_get_char_validated(const gchar *p,gssizemax_len); Dekóduje a vrátí unicode znak v řetězci, maximální délka znaku je max_len. GLib – Unikód
glong g_utf8_strlen(const gchar *p, gssizemax);Zpočítá počet znaků v utf8 řetězci (Pozor, počet znaků se nemusí rovnat počtu bytů, to znamená, že funkce strnlen(p, n) může vrátit jinou hodnotu než funkce g_utf8_strlen(p, n) gchar* g_utf8_strncpy(gchar *dest, const gchar *src,gsizen);Zkopíruje n znaků z src do dest, jako strccpy(). gchar* g_utf8_strchr(const gchar *p, gssizelen, gunicharc);Utf8 ekvivalent funkce strchr(). gchar* g_utf8_strrchr(const gchar *p, gssizelen,gunicharc);Utf8 ekvivalent funkce strrchr(). gchar* g_utf8_strreverse(const gchar *str, gssizelen);Utf8 ekvivalent funkce g_strreverse(). GLib – Unikód
Následující funkce slouží pro převod mezi jednotlivým kódováním: gunichar2 *g_utf8_to_utf16(const gchar *str,glonglen,glong *items_read,glong *items_written,GError **error); gunichar *g_utf8_to_ucs4(const gchar *str,glonglen,glong *items_read,glong *items_written,GError **error); gunichar *g_utf8_to_ucs4_fast(const gchar *str,glong len,glong *items_written); gunichar *g_utf16_to_ucs4(const gunichar2 *str,glonglen,glong *items_read,glong *items_written,GError **error); GLib – Unikód
Následující funkce slouží pro převod mezi jednotlivým kódováním: gchar *g_utf16_to_utf8(const gunichar2 *str,glonglen,glong *items_read,glong *items_written,GError **error); gunichar2 *g_ucs4_to_utf16(const gunichar *str,glonglen,glong *items_read,glong *items_written,GError **error); gchar *g_ucs4_to_utf8(const gunichar *str,glonglen,glong *items_read,glong *items_written,GError **error); utf16 – 16 bitové kódování ucs4 – 32 bitové kódování. utf8 – 8 bitové kódování, kde znak může mít více bajtů. GLib – Unikód
GLib umožňuje i spoustu dalších funkcí na plně univerzální využití, některé funkce jsou perfektně popsány na www.root.cz (z tadyma jsem čerpal já) v sekci vývoj->knihovny->GLib. Ovšem některé funkce a možnosti byly dodělány až po skončení seriálu na www.root.cz a nenalezneme je tam: GLib umožňuje kompletní vytvoření objektů v čistém jazyce C (GObject). GLib má multiplatformní kód pro práci s vlákny. Pomocí GLib můžeme zjistit kde náš program zkrachoval (GBacktrace) Implementace lokalizace Náhodné čísla (GRand) Práce s OI (g_io) To co na www.root.cz najdeme: Lexikální scanner (GScanner) Doplňování řetězců (GCompletion) Fronty (synchronní a asynchronní) Práce s datem a časem Cache Práce s mnohonásobnými stromy. Kvarky (GQuark) Vypracoval:Petr Kobalíček (e666e@users.sf.net)14.3.2005 Zlín GLib – Další funkce