11.0 Výčtové typy
    Výčtové typy jsou jakoby sdružená makra. Prostě uděláte množinu konstant,
    které dáte datový typ. (ve skutečnosti to bude integer, což přináší dost
    výhod pro operace s výčtovými typami :-)) Definují se takto :


typedef enum {
    ZLUTA,
    MODRA,
    ZELENA,
    RUZOVA
} BARVY;
Zase to můžete podle novějšího C ++ zkusit takhle (ale bude to fungovat jen v kompilátorech, podporujících C ++ -> MSVC++, DJGpp, možná Borland) :

enum eLumps
{
    kEntities = 0,
    kTextures,
    kPlanes,
    kNodes,
    kLeafs,
    kLeafFaces,
    kLeafBrushes,
    kModels,
    kBrushes,
    kBrushSides,
    kVertices,
    kMeshVerts,
    kShaders,
    kFaces,
    kLightmaps,
    kLightVolumes,
    kVisData,
    kMaxLumps
};
Je to kus ze zdrojáku Quaka ]I[. Ta nula znamená že hodnota kEntities bude 0 a hodnota každé další položky bude o 1 vyšší. Můžete jim přiřadit klidně všechny hodnoty, ale kompilátor to normálně udělá za vás :

enum Barvy {
    Zluta = 0xffff00,
    Modra = 0x0000ff,
    Zelena = 0x00ff00,
    Ruzova = 0xff00ff
};
Teď tam jsou čísla, odpovídající RGB vyjádřením těch barev. Když definujete všechny hodnoty, snažte se je seřadit podle velikosti, aby nevznikly zápisy, jako :

enum Barvy {
    Zluta = 5,
    Modra = 1,
    Zelena = 3,
    Ruzova
};
Něco takového se pak použije asi takhle :

Barvy b;

b = Zluta;
Takhle deklarované výčtové typy jsou např. boolean TRUE a FALSE. 11.1 Struktury Struktury jsou výtečná vychytávka. V paskalu se tomu říká record a v basicu se to dělá slůvkem type. Struktura je nový datový typ, složený z jiných datových typů. Jednoduchá struktura může být :

typedef int POLE[10];
Potom, když kdekoli v programu napíšete :

POLE i;
Bude to to samé, jako :

int i[10];
Občas se dělá, že si definujete typy jako uint, ulong .. abyste nemuseli vypisovat pracně unsigned int, unsigned long. To by bylo takhle :

typedef unsigned int uint;
typedef unsigned long ulong;
To byla nejjednodušší struktura. Teď k těm složitějším.

typedef struct {
    float x, y, z;
} Vector;
A nebo zase podle C ++ (taky z Quake a taky jen v C ++ kompilátorech) :

struct Vector3f {
    float x, y, z;
};
Dáme si něco, aby to pochopili Češi :

struct Zamestnanec {
    int vek, vaha;
    float vyska;
    long plat;
};
Toto je struktura zaměstnance firmy (třeba pro osobní záznamy). použije se takhle :

Zamestnanec z, u;

z.vek = 58;
z.vaha = 100;
z.vyska = 1.82;
z.plat = 10000;

u = z;
To jsme udělali docela slušného zaměstnance a jeho kopii, ale je tu jeden malý háček při použití pointerů :

Zamestnanec *z;

z = (Zamestnanec*) malloc(sizeof(Zamestnanec));

z->vek = 58;
z->vaha = 100;
z->vyska = 1.82;
z->plat = 10000;
Tak to by bylo. Prostě když použijete pointer, odkazujete se šipečkou a ne tečkou. (to je kvůli ladění) Kdyby jste někdy potřebovali, aby struktura ukazovala sama na sebe, dělá se to takhle :

struct Mnohouhelnik {
    int x, y;
    struct Mnohouhelnik *next; // Ukazatel na další bod
    // Nesmí být Mnohouhelnik next;
};
A teď se můžeme směle odkazovat ... Možná vám není jasné, k čemu byste mohli něco takového potřebovat. Je to velmi dobré, když z disku načítáte data, o kterých nevíte, kolik jich je. Dobrým a praktickým příkladem jsou textové "databáze", do kterých se ručně doplňuje. Vzpomínám např. databázi cheatů herního časopisu PC-GAMER. Ta má velmi jednoduchou strukturu. Příklad : @101 St Airborne Cheaty Cheaty Cheaty @Evolva Cheaty Cheaty Cheaty Cheaty @Descent : Freespace Cheaty Cheaty @Doom Cheaty Cheaty Cheaty @Duke nukem 3D Cheaty Cheaty Cheaty Cheaty @' Takhle to vypadá. Je tam první zavináč, před kterým je komentář a potom jsou data až do dalšího zavináče. Pokud tam je ampersand (&) tak je konec. Dalo by se to udělat tak, že napřed spočítáte zavináče, naalokujete pole a čtete, nebo budete pole postupně zvětšovat, ale můžete to udělat i takhle :

/* PC_Gamer.cpp */

#include 
#include 
#include 

struct PCGAMER {
    char *gname; // jméno hry
    char cheat[1024]; // Hesla do hry - prasecina, melo by to byt char*
    struct PCGAMER *next;
};

PCGAMER data; // Databáze
PCGAMER *act; // Aktuální záznam

char *LoadCheat(FILE *f)
{
    char *chtlin;
    // Jeden řádek

    chtlin = (char*) malloc(256 * sizeof(char));
    // naalokujeme si buffer pro nacitani,
    // zaroven se pouzije po jmeno hry

    act->cheat[0] = 0;
    // vynuluje se string pro cheaty

    while(1) {
        fgets(chtlin, 255, f);
        // Tato funkce je ve stdio.h
        // popsáno v kapitole pokročilá
        // práce se souborem.

        if(chtlin[0] == '@')
            return chtlin;
        // Konec záznamu ...

        strcat(act->cheat, chtlin);
        // Připojení záznamu

        strcat(act->cheat, "\n");
        // Nový řádek
    }
    return chtlin;
}

int Load_PC(char *filename)
{
    FILE *fr;
    char *pom;
    PCGAMER tmp;

    if((fr = fopen(filename, "r")) == NULL)
        return 1;
    // Nejde otevrit ...

    act = &tmp;
    // nastavení akt. záznamu, zahodí se
    // Slouží jen k nalezení 1. zavináče ...

    pom = LoadCheat(fr);
    // Nahraje vše před @

    data.gname = ++ pom;
    // Posunutí o 1 znak (@), zápis
    // najde název první hry ...

    act = &data;
    // Teď už se zapisuje ...

    while(1) {
        pom = LoadCheat(fr);
        pom ++;
        // Vynechání zavináče

        if(pom[0] == '\'')
            break;
        // apostrof znamená konec souboru ...

        if((act->next = (PCGAMER*) malloc(sizeof(PCGAMER))) == NULL)
            return 0;
        // Alokace dalšího záznamu

        act = act->next;
        // Posunout na aktuální záznam

        strcpy(act->gname, pom);
        // nové jméno hry

    }
    act->next = NULL; // Zakončení
    fclose(fr);
    return 1;
}
Tento program umí načíst databázi, už zbývá přidělat jen main() a hledání. Používá to funkci fgets(), kterou si vysvětlíme až v kapitole o souborech. Teď jen krátce - načte jeden řádek ze souboru. První parametr je string, druhý je jeho délka (musí být naalokovaný) a třetí je pointer na soubor. Snad to bude jasný. Struktura PCGAMER je vlastně jednosměrný spojový seznam. Oboustraný spojový seznam by vypadal takhle :

struct Seznam {
    // nejaky data
    .
    .
    // nejaky data

    struct Seznam *dalsi, *predchozi;
    // ukazatel na sousedni prvky
};
Teď ještě zbývají speciální typy a zápisy definicí struktur :

struct bitove_pole {
    unsigned neco        : 8;  // 00000000 ????????
    unsigned neco_jineho : 3;  // 00000??? 00000000
    unsigned flag        : 1;  // 0000?000 00000000
    unsigned cislo       : 3;  // 0???0000 00000000
    unsigned priznak     : 1;  // ?0000000 00000000
};
Tohle je tzv. Bitové pole. Používalo se to při šetření pamětí, ale teď už jsem to dlouho neviděl. Každá položka se chová jako číslo (signed nebo unsigned, jak chcete), jen zabírá určitý počet bitů ve struktuře (číslo za dvojtečkou). Používá se to když chcete, aby to zabralo málo místa. A pak vznikají chyby jako Bug2000 - v té struktuře bylo málo bitů pro rok. Vypadalo by to nějak takhle :

struct datum {
    unsigned den   : 5;  // 00000000 000?????
    unsigned mesic : 4;  // 0000000? ???00000
    unsigned rok   : 7;  // ???????0 00000000
};
Potom den je číslo <0 - 31>, měsíc <0 - 15> a rok <0 - 127>. Reálný rok se pak spočítal jako 1980 + datum.rok. Takže max. letopočet mohl být 2107. V té struktuře byl asi ještě čas a tak se to nevěšlo... Když si zkusíte ve Win98 (asi i jiných) měnit datum, narazíte na 1980 a když půjdete ještě níž, bude tam najednou 2099. (kdoví proč, když rozdíl je 119, což není mocnina dvou. asi je ještě něco vyhrazené...) Nakonec byste ještě měli vědět, že data ve struktuře nejsou hned za sebou, vezmeme si nějakou strukturu :

struct pokus {
    char a;
    short b;
    short c;
};
Data nebudou zasebou a to ze dvou důvodů. Program používá tzv. memory align zarovnání dat v paměti na sudé adresy, takže mezi a a b bude bajt mezera. Za druhé se používá zaokrouhlení velikosti struktury na násobky dvou, takže za c bude asi ještě nevyužitý bajt. Z toho plyne že pro zjišťování velikosti struktury používejte sizeof(struktura) a ne součet velikostí jednotlivých prvků. Taky bude rozdíl když na soubor zapíšete strukturu a když zapíšete jednotlivé položky. Ale o tom až u souborů. Potom ještě taková drobnost - anonymní struktury :

struct Zamestnanec {
    int vek, vaha;
    float vyska;
    long plat;
} *z;
Tohle natypuje strukturu a hned udělá nový prvek té struktury. To ještě není anonymní. Ale :

struct {
    int vek, vaha;
    float vyska;
    long plat;
} z;
Tohle bude anonymní struktura. Není v tom žádná výhoda, vyplatí se to jen když strukturu potřebujete jen jednou. (třeba při hledání v nějaké tabulce konstant bude anonymní struktura a jedna funkce pro hledání) Dá se to taky naplnit nějakými hodnotami :

struct {
    int vek, vaha;
    float vyska;
    long plat;
} z[] = {
    {23,  96, 123.5, 20000},
    {25,  66,    72, 25000},
    {43,  43, 107.2, 12500},
    {82, 158,    56, 10000} };
To byla zase struktura zaměstnance, z je teď pole o čtyřech záznamech, čtyřech různých (trochu divných :-)) zaměstnancích. A to je o strukturách asi tak všechno. 11.3 Uniony Uniony jsou stejný jako struktury, ale všechny data jsou v jednom úseku paměti. K čemu to je ? Prostě máme třeba union :

    union Muj_Union {
        char m_char;
        int m_int;
        long m_long;
        float m_float;
        double m_double;
    };
Pokud zapíšete do m_char (pojmenovat si to můžete jakkoli, odkazuje se tečkou nebo šipkou při pointeru - jako u struktur), bude tam znak, který tam dáte. Pokud ale zapíšete třeba do m_int, hodnotu v m_char přepíšete (všechna data jsou ve stejné paměti) Nevím, union sem asi nikde nepoužil. Možná že se to dá použít ve scriptovacím enginu (kompilátoru skriptů). Jo ! až na union REGS, představující registry procesoru. To se ale používalo jen za dob dosu :-) Zkopírováno z DJGpp :
struct DWORDREGS {
  unsigned long edi;
  unsigned long esi;
  unsigned long ebp;
  unsigned long cflag;
  unsigned long ebx;
  unsigned long edx;
  unsigned long ecx;
  unsigned long eax;
  unsigned short eflags;
};

struct DWORDREGS_W {
  unsigned long di;
  unsigned long si;
  unsigned long bp;
  unsigned long cflag;
  unsigned long bx;
  unsigned long dx;
  unsigned long cx;
  unsigned long ax;
  unsigned short flags;
};

struct WORDREGS {
  unsigned short di, _upper_di;
  unsigned short si, _upper_si;
  unsigned short bp, _upper_bp;
  unsigned short cflag, _upper_cflag;
  unsigned short bx, _upper_bx;
  unsigned short dx, _upper_dx;
  unsigned short cx, _upper_cx;
  unsigned short ax, _upper_ax;
  unsigned short flags;
};

struct BYTEREGS {
  unsigned short di, _upper_di;
  unsigned short si, _upper_si;
  unsigned short bp, _upper_bp;
  unsigned long cflag;
  unsigned char bl;
  unsigned char bh;
  unsigned short _upper_bx;
  unsigned char dl;
  unsigned char dh;
  unsigned short _upper_dx;
  unsigned char cl;
  unsigned char ch;
  unsigned short _upper_cx;
  unsigned char al;
  unsigned char ah;
  unsigned short _upper_ax;
  unsigned short flags;
};

union REGS {  /* Compatible with DPMI structure, except cflag */
  struct DWORDREGS d;
#ifdef _NAIVE_DOS_REGS
  struct WORDREGS x;
#else
  #ifdef _BORLAND_DOS_REGS
    struct DWORDREGS x;
  #else
    struct DWORDREGS_W x;
  #endif
#endif
  struct WORDREGS w;
  struct BYTEREGS h;
};
No a to je konec, struktury byste měli dobře umět, výčtové typy snad pochopí každý a ten zbytek se nepoužívá :-). Cvičení : 1) - Napište program, který bude mít strukturu Kocka s věkem a cenou. Uživatel zadá počet koček a ceny a stáří koček. Program je potom seřadí podle ceny a podle věku a vytiskne (napřed podle ceny a potom podle věku) 2) - Napište program pro evidenci pokojů v hotelu. Bude struktura pokoj, která má číslo pokoje (0 - 50) a je obsazená nebo volná. To bude výčtový typ. Hotel bude mít 5 pokojů a program bude umět zobrazit zabrané a volné pokoje a zadat / uvolnit pokoj. 3) - Napište program, který bude mít výčtový typ eLumps (na začátku) a vytiskne jména a názvy položek typu. Zkuste použít pole pro názvy. 4) - Napište program, který bude mít spojový seznam, kde půjde přidávat prvky, ubírat prvky (obojí na určitou pozici) Po každé operaci se obsah seznamu znovu zobrazí (na jednu řádku) Tak se mějte hezky a užívejte si posledního sluníčka ! -tHE SWINe-
Zpátky