Další utility
gint g_bit_nth_lsf(guint32 mask, gint nth_bit);
…vrátí pozici (index) prvního nastaveného (1) bitu v masce mask
, hledáno od bitu s pořadím nth_bit
nahoru (ale ne včetně). Bity jsou číslovány od 0 (dolní bit, Least SigniFicant) po 31. Chcete-li prohledávat bity od prvního (s indexem 0), vložte za nth_bit
hodnotu –1.
gint g_bit_nth_msf(guint32 mask, gint nth_bit);
…dělá totéž, ale od nejvyššího bitu (Most SigniFicant) dolů. Indexy bitů jsou stejné, tedy od 0 (nejspodnější bit) po 31. Chcete-li začít prohledávání od nejvyššího bitu (s indexem 31), vložte za nth_bit
číslo 32 nebo –1.
guint g_bit_storage(guint number);
…vrátí počet bitů nutných k uložení čísla number
. Např. pro číslo 4 jsou potřeba 3 bity (4 binárně = 100).
guint g_spaced_primes_closest(guint num);
…vrátí nejmenší prvočíslo z vnitřního pole prvočísel, které je větší než num
. Vnitřní pole prvočísel obsahuje prvočísla z intervalu od 11 do 13845163 taková, že každé následující prvočíslo je zhruba 1,5 až dvojnásobkem prvočísla předchozího. Samotná GLib funkci využívá pro stanovení optimální velikosti hash tabulek ( GHashTable
).
guint g_parse_debug_string(const gchar *string, GDebugKey *keys, guint nkeys); struct GDebugKey { gchar *key; guint value; };
Funkci g_parse_debug_string()
používají knihovny GDK a GTK k analýze nastavení ladicích výstupů. Parametr string
je dvojtečkami ( :
) oddělený seznam voleb. Argument keys
je pole struktur GDebugKey
o velikosti nkeys
. Funkce vrátí bitovou mapu sestavenou podle voleb v řetězci string
a jím odpovídajícím maskám value
. Jinými slovy, v poli keys
určíte, jaké volby ( key
) mají odpovídat jakým bitům ( value
). Je-li v řetězci string
hodnota "all"
, nastaví se všechny volby.
Příklad:
GDebugKey keys[] = {{"warning", 1}, {"fatal", 2}, {"assert", 4}, {"log", 8}}; guint flags; flags = g_parse_debug_string("fatal:assert", keys, 4); /* vysledkem bude: 2 || 4 = 6 */ flags = g_parse_debug_string("all", keys, 4); /* vysledkem bude: 1 || 2 || 4 || 8 = 15 */
Jistě znáte ze standardního C funkci atexit()
. GLib pro konvenci definuje její analogii:
void g_atexit(GVoidFunc func); void(*GVoidFunc)(void);
Funkce g_atexit()
zařadí funkci func
do seznamu funkcí, které jsou vyvolány při normálním ukončení programu (voláním funkce exit()
nebo návratem z funkce main
). Funkce takto registrované jsou volány v obráceném pořadí jejich registrace. Nejsou jim předávány žádné argumenty (viz prototyp GVoidFunc
).
Funkce pro kompatibilitu s Windows
Vedle různých podpůrných utilit se knihovna GLib snaží zvýšit přenositelnost programů z Unixů do Windows také dalším způsobem. Pokud své zdrojové kódy kompilujete pod Windows, má knihovna GLib definováno množství maker, které mají stejné názvy jako některé standardní funkce Unixu. Spousta těchto maker jenom jednoduše přejmenovává standardní Windowsoidní funkce. Výsledkem pak je fakt, že zdrojové kódy svých programů nemusíte po změně platformy vůbec měnit.
#define MAXPATHLEN 1024
…maximální délka názvu cesty.
#define NAME_MAX 255
…maximální délka samotného jména souboru.
Následují makra, která suplují standardní funkce Unixu. Jejich funkčnost je naprosto stejná s funkcemi Unixu tohoto jména, proto zde uvádím jenom jejich výčet. Pilný čtenář si jejich vlastnosti může vyhledat v příručkách o programování v operačních systémech Unix.
#define getcwd
#define getpid
typedef pid_t;
#define access
#define open
#define read
#define write
#define lseek
#define close
#define pipe(phandles)
#define popen
#define pclose
#define fdopen
#define ftruncate(fd, size)
#define opendir
#define readdir
#define rewinddir
#define closedir
Big-endian vs. Little-endian
Jak asi víte, některé procesory se od ostatních liší v tom, že fyzicky v paměti uchovávají bity v jiném pořadí. Jedny ukládají horní bajt dříve než dolní – a takovému uspořádání se říká big-endian.
Jiné procesory (např. procesory rodiny x86) zase ukládají horní bajt nakonec. Toto uspořádání je známo pod názvem little-endian.
Pro zkomplikování celé záležitosti, některé procesory ukládají bajty v úplně exotickém pořadí. Bajty 4-bajtového slova uloží v pořadí 3, 4, 1 a 2. Takovému řazení se říká PDP-endian.
Pokud se se svými aplikacemi plácáte jenom na jednom typu procesoru, je vše v pořádku. Problémy nastanou až při komunikaci různých typů procesorů po síti nebo prostřednictvím binárních souborů. V knihovně GLib proto naleznete sadu maker, které realizují konverze mezi jednotlivými indiány.
Zjištění uspořádání bajtů
Začneme nejprve makrem
#define G_BYTE_ORDER
…které prozrazuje, s jakou mašinou vlastně máme tu čest. Podle platformy se makro rozvine na jednu z hodnot:
#define G_LITTLE_ENDIAN
#define G_BIG_ENDIAN
nebo
#define G_PDP_ENDIAN
(rozpoznávání G_PDP_ENDIAN
ještě není v GLib implementováno)
Převod mezi ‚host‘ a ‚network byte order‘
V Internetu je standardní uspořádání bajtů známé pod označením ‚network byte order‘. (De facto je to big-endian.) Pro převod na/z něj slouží makra:
#define g_htonl (val)
#define g_htons (val)
#define g_ntohl (val)
#define g_ntohs (val)
Význam maker dekódujete podle následujícího klíče: první písmeno v názvu (za g_
) označuje, z kterého prostředí se má dekódovat ( h
= host (náš počítač), n
= network (síť)), následuje to
, a po něm cílové prostředí (opět h
nebo n
). Poslední písmeno v názvu označuje typ hodnoty val
( l
je pro 32-bitový integer (Long) a s
pro 16-bitový integer (Short)).
Převod mezi little-endian a big-endian
#define GINT_FROM_BE (val)
…převede gint
ovou hodnotu val
z big-endian ( BE
) na uspořádání použité aktuální platformou.
#define GINT_FROM_LE (val)
…zkonvertuje gint
ve formátu little-endian ( LE
) na formát pro aktuální platformu.
#define GINT_TO_BE (val)
…transformuje gint
na big-endian reprezentaci.
#define GINT_TO_LE (val)
…převede gint
val
na little-endian.
Stejná makra jako předcházející čtveřice máme i pro ostatní celočíselné datové typy. Pro guint
( unsigned int
) jsou to:
#define GUINT_FROM_BE (val)
#define GUINT_FROM_LE (val)
#define GUINT_TO_BE (val)
#define GUINT_TO_LE (val)
Pro glong
:
#define GLONG_FROM_BE (val)
#define GLONG_FROM_LE (val)
#define GLONG_TO_BE (val)
#define GLONG_TO_LE (val)
I pro gulong
( unsigned long
):
#define GULONG_FROM_BE (val)
#define GULONG_FROM_LE (val)
#define GULONG_TO_BE (val)
#define GULONG_TO_LE (val)
Nebo pro 16-ti bitový int
( gint16
):
#define GINT16_FROM_BE (val)
#define GINT16_FROM_LE (val)
#define GINT16_TO_BE (val)
#define GINT16_TO_LE (val)
…atd. (názvy jsou jistě vševysvětlující):
#define GUINT16_FROM_BE (val)
#define GUINT16_FROM_LE (val)
#define GUINT16_TO_BE (val)
#define GUINT16_TO_LE (val)
#define GINT32_FROM_BE (val)
#define GINT32_FROM_LE (val)
#define GINT32_TO_BE (val)
#define GINT32_TO_LE (val)
#define GUINT32_FROM_BE (val)
#define GUINT32_FROM_LE (val)
#define GUINT32_TO_BE (val)
#define GUINT32_TO_LE (val)
#define GINT64_FROM_BE (val)
#define GINT64_FROM_LE (val)
#define GINT64_TO_BE (val)
#define GINT64_TO_LE (val)
#define GUINT64_FROM_BE (val)
#define GUINT64_FROM_LE (val)
#define GUINT64_TO_BE (val)
#define GUINT64_TO_LE (val)
Veškeré konverze mezi big-endian, little-endian i PDP-endian jsou symetrické. Pro konverze mezi jednotlivými uspořádáními můžete používat přímo následující makra, která provádí konverze mezi dvěma typy. Např.
#define GUINT16_SWAP_BE_PDP (val)
…převede guint16
z big-endian na PDP-endian i zpět. Je-li val
ve formátu big-endian, výsledkem volání GUINT16_SWAP_BE_PDP(val)
bude hodnota v PDP-endian, a naopak, je-li val
v PDP-endian, po konverzi tímto makrem se dostane do big-endian reprezentace.
Podobně tak i další makra:
#define GUINT16_SWAP_LE_BE (val)
…provádí konverzi little-endian/big-endian (a zpět) nebo
#define GUINT16_SWAP_LE_PDP (val)
…která realizuje převod little-endian/PDP-endian (a zpět) pro guint16
.
Pro integery jiné velikosti jsou zde další odrůdy:
#define GUINT32_SWAP_BE_PDP (val)
#define GUINT32_SWAP_LE_BE (val)
#define GUINT32_SWAP_LE_PDP (val)
a
#define GUINT64_SWAP_LE_BE (val)
To by tak bylo z mé strany pro dnešek vše. U dalších pokračování se těší