Hlavní navigace

GLib: Práce s pamětí, typová konverze

Michal Burda 21. 3. 2000

Tvůrcům knihovny GLib (šířené podle licence LGPL) patrně nestačily funkce standardního Céčka pro alokování a uvolňování paměti, tak si dodefinovali pár vlastních a my se je dnes naučíme používat. Kromě toho si také povíme něco o typové konverzi z pointeru na integer a naopak.

Ačkoliv jsem v minulém díle avizoval, že se dnes budeme bavit o řetězcích, rozhodl jsem se nakonec vysvětlit nejprve funkce pro práci s pamětí, abychom v příštích dílech mohli na těchto znalostech stavět a pustit se odvážně do (relativně) obtížnějších témat.

PRÁCE S DYNAMICKOU PAMĚTÍ

Práce s dynamickou pamětí je skoro v každém programu nutností. Předpokládám, že máte znalosti funkcí standardního C starajících se o alokování a uvolňování paměti. Nebudu se proto pouštět do vysvětlování, co alokace dynamické paměti obnáší a k čemu slouží, ale přejdu rovnou k věci, tedy jaké nové funkce pro správu paměti přináší knihovna GLib.

Alokace paměti

#define 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.

Chcete-li, aby nově alokovaná paměť byla navíc inicializována samými nulami, je třeba místo toho zavolat makro

#define g_new0(type, count)

… které alokuje count prvků typu type a všechny bajty nastaví na 0. Vrácený pointer je typu pointer na type. V případě, že count je 0, vrátí  NULL.

gpointer g_malloc(gulong size);

… 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.

Jak asi čekáte,

gpointer g_malloc0(gulong size);

… 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.

Realokace paměti

Realokace paměti je proces, kdy se alokované paměťové místo zvětší na zadanou velikost. Dělá se to v podstatě tak, že původní alokovaná paměť se uvolní a místo ní se alokuje nová, o větší velikosti. Musíte vždy počítat s tím, že touto operací může dojít (a obvykle také dochází) ke změně adresy.

#define 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(gpointer mem, gulong size);

… 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í.

Dealokace paměti

K uvolnění paměti slouží jednoduchá funkce

void g_free(gpointer mem);

… která uvolní místo, na které ukazuje pointer mem. Je-li v  mem uložen NULL, jednoduše skončí. Všechnu paměť, kterou jste dříve alokovali pomocí předchozích funkcí, byste po použití měli uvolnit (dealokovat) pomocí této funkce, aby přestala být rezervovaná a systém ji mohl použít k něčemu jinému.

Další funkce

#define g_memmove(d, s, n)

… toto makro zkopíruje blok paměti n bajtů dlouhý z adresy s do d. Zdrojová a cílová oblast se může překrývat.

Pozor! Na platformách, kde není k dispozici memmove(), je funkce implementována použitím bcopy(), která není schopna obsloužit překrývající se oblasti.

gpointer g_memdup(gconstpointer mem, guint byte_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:

/* Zkouska funkci pro dynamickou alokaci pameti */
#include <glib.h>
gint main(void) {
  gint *pole;   /* dynamicke integerove pole */
  gint *pole2;  /* dalsi dynamicke pole */
  gint x;       /* pomocna promenna */

  /* vytvoreni 5ti prvkoveho pole */
  pole = g_new0(gint, 5);
  for (x = 0; x < 5; x++) {
    /* ukazka toho, ze nove pole je opravdu vynulovano */
    printf("pole[%d] = %d\n", x, pole[x]);
    /* nastaveni nejakych hodnot */
    pole[x] = 2 * x;
  }
  /* duplikace pole */
  pole2 = g_memdup(pole, 5 * sizeof(gint));
  for (x = 0; x < 5; x++) {
    /* kontrolni vystup */
    printf("pole[%d] = %d\tpole2[%d] = %d\n", x, pole[x], x, pole2[x]);
  }
  /* uvolneni pameti (dealokace) */
  g_free(pole);
  g_free(pole2);

  return(0);
}

MAKRA PRO TYPOVOU KONVERZI gint, guintgpointer

Následující makra poskytují přenositelné metody ukládání hodnot typu gint a guint do proměnných typu gpointer. Mnoho složitějších datových typů (jako hash tabulky, seznamy, stromy a podobně) jsou totiž založeny právě na uchovávání proměnných typu gpointer, které slouží jako pojítko mezi skutečnými daty.

Užitím těchto konverzních maker lze do proměnných typu gpointer ukládat hodnoty typu gint nebo guint. Můžete tak například lehce vytvořit spojový seznam gint hodnot nebo strom guint ů.

Konverzní makra jsou nutná, protože velikost proměnné typu gpointer se na různých platformách může lišit. Proto je třeba k takové typové konverzi přistupovat opatrně.

Opačnou operaci, tedy uložení gpointer u do integerových proměnných nelze provést, protože není zaručeno, že gint nebo guint bude na libovolné platformě dostatečně velký na to, aby do sebe uložil celou adresu paměti.

Pro konverzi gint u na gpointer použijte makro GINT_TO_POINTER(int_value). Zpět na gint jej zkonvertujete makrem  GPOINTER_TO_INT(pointer_value).

Chcete-li provést konverzi proměnné typu guint na gpointer, zavolejte makro GUINT_TO_POINTER(unsigned_int_value). Opačnou konverzi, tedy gpointer na guint, provedete voláním  GPOINTER_TO_UINT(pointer_value).

Příklad:

gpointer p;
guint ui;

p = GUINT_TO_POINTER(ui);
...
ui = GPOINTER_TO_UINT(p);
...

A to je pro dnešek vše. Těším se u dalšího pokračování.

Našli jste v článku chybu?
Lupa.cz: E-shopy: jen sleva už nestačí

E-shopy: jen sleva už nestačí

Vitalia.cz: Jak koupit Mikuláše a nenaletět

Jak koupit Mikuláše a nenaletět

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

DigiZone.cz: Další dva kanály nabídnou HbbTV

Další dva kanály nabídnou HbbTV

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Podnikatel.cz: Prodává přes internet. Kdy platí zdravotko?

Prodává přes internet. Kdy platí zdravotko?

Root.cz: Vypadl Google a rozbilo se toho hodně

Vypadl Google a rozbilo se toho hodně

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Podnikatel.cz: EET zvládneme, budou horší zákony

EET zvládneme, budou horší zákony

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

DigiZone.cz: NG natáčí v Praze seriál o Einsteinovi

NG natáčí v Praze seriál o Einsteinovi

DigiZone.cz: Flix TV má set-top box s HEVC

Flix TV má set-top box s HEVC

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0