Učíme se C (26. díl) - Datové typy enum a union - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

Učíme se C (26. díl) - Datové typy enum a union

10. července 2001, 00.00 | Vlastnosti datových typů enum a union, jejich definice, použití a
na co si dát při práci s nimi pozor.

Výčtový datový typ enum

Jedním z datových typů, o kterých jsme zatím nemluvili, je typ enum. Jedná se vlastně o jakousi náhradu za symbolické konstanty vytvářené pomocí makra #define. Uživatel si pro nový výčtový typ sám definuje množinu přípustných hodnot uvedením všech jejich prvků. Není tedy problém vytvořit si pomocí enum nový typ, jež může nabývat například hodnot CERVENA, MODRA, ZELENA.

Vnitřně jsou pak tyto konstanty reprezentovány celými čísly, a to nejmenšího znaménkového typu, který je schopen všechny prvky nového typu obsáhnout. V našem případě postačí typ char, který pro reprezentaci tří symbolických konstant bohatě postačí.

Definice proměnných typu enum

Definice proměnné typu enum je velice podobná definicím struktur. Jistě si vzpomínáte, že proměnné struktury jsme mohli definovat více způsoby. To platí i pro typ enum.

My si ukážeme variantu s použitím typedef, která je pro definici asi nejvhodnější. Jediný rozdíl oproti definici struktury je ten, že místo klíčového slova struct použijeme slovo enum a že ve složených závorkách, kde jsme dříve definovali jednotlivé prvky struktury, teď prostě uvedeme seznam všech symbolických konstant oddělených čárkou. V našem případě tedy:

typedef enum { CERVENA,
               MODRA,
               ZELENA
             } barvy;

Nyní jsme tedy nedefinovaly nový výčtový typ barvy. Teď už stačí jen vytvořit proměnnou tohoto typu.

barvy barva1;

Nově vytvořená proměnná barva1 teď může nabývat hodnoty CERVENA, MODRA nebo ZELENA, jak si ale ukážeme, může to být složitější. Navíc, takto zavedené symbolické konstanty jsou v programu použitelné i bez nutnosti vytvářet proměnnou. Pokud bychom chtěli vytvořit symbolické konstanty TRUE a FALSE, můžeme je buď nadefinovat pomocí makra:

#define FALSE 0
#define TRUE 1

nebo prostě jen vytvořit nový typ:

enum { FALSE, TRUE };

Řekli jsme si, že vnitřně jsou hodnoty výčtových typů reprezentovány celými čísly. V praxi to vypadá tak, že každé symbolické konstantě v definici výčtového typu je přiřazena některá číselná konstanta podle pořadí v seznamu. V našem případě je konstanta CERVENA == 0, MODRA == 1 a ZELENA == 2. Důsledkem je, že výčtové a celočíselné typy jsou navzájem kompatibilní a lze tedy bez problémů použít následující zápisy:

typedef enum { CERVENA,
               MODRA,
               ZELENA
             } barvy;

barvy barva1=CERVENA, barva2=1;
int n;

barva2==MODRA   // pravda
barva1==0       // pravda
barva2++        /* zvětší hodnotu proměnné barva2 o 1, a tedy 
                   ji změní na ZELENA */
barva2==ZELENA  // pravda
n = barva2      // mezi ob2ma typy lze normálně přiřazovat 
n == 2          // pravda

Poněkud nepříjemné je, že lze do proměnné výčtového typu přiřadit i celočíselnou hodnotu, která nemá definovanou odpovídající symbolickou konstantu. Vlastně tak přiřadíme hodnotu, která patří mimo rozsah typu, přitom však není hlášena žádná chyba při překladu ani za běhu programu:

barvy barva1;

barva1 = 10;

Aby to bylo ještě složitější, lze při definici výčtového typu i přímo určit číselnou reprezentaci konstant. Platí pravidlo, že číselná hodnota symbolické konstanty je číslo o 1 větší než hodnota předchozí symb. konstanty v seznamu, přičemž hodnota první položky je rovna 0, není-li uvedeno jinak. Samotné nastavení provedeme prostým přiřazením číselné konstanty, jak je to ukázáno v následujícím příkladu:

typedef enum { PONDELI = -1,
               UTERY,
               STREDA,
               CTVRTEK = 10,
               PATEK = 9,
               SOBOTA,
               NEDELE
             } tyden;

První položka v seznamu - PONDELI - bude reprezentována jako -1. UTERY bude číslo o 1 vyšší, tedy 0, a stejně tak STREDA, které se přiřadí hodnota 1. CTVRTEK a PATEK jsou dány pevně a zbylé konstanty budou reprezentovány jako SOBOTA==10 a NEDELE==11. Všimněte si, že položky CTVRTEK a SOBOTA jsou reprezentovány stejným číslem 10, což je při definici výčtového typu bez problémů možné.

Datový typ union

Druhým datovým typem, o kterém dnes bude řeč, je union. Tento typ je jistou obdobou variantních záznamů známých např. z pascalu. Union si lze jednoduše představit jako obyčejnou strukturu, kde ale všechny její položky sdílejí jedno paměťové místo, tedy se překrývají (jsou na stejné adrese). Zatímco u obyčejných struktur bylo pro každou položku alokováno zvláštní místo v paměti, v případě unionů je tedy alokováno místo pouze pro největší z nich.

Definice unionů je prakticky shodná s definicí struktur:

typedef union { char c;
                int pocet;
                double delka;
              } un;
Protože se jednotlivé prvky unionu překrývají, je jasné, že po přiřazení hodnoty některému z nich se dá pracovat již pouze s tímto prvkem, a to až do doby, kdy dojde k novému přiřazení. V opačném případě bychom pracovali s „deformovanými“ daty (i když i tato vlastnost se dá v některých případech patřičně využít). Zde se projeví nevýhoda unionů, které neuchovávají informaci o tom, který jejich prvek je právě využíván. Možností, jak toto obejít, je zabalit union do další struktury obsahující navíc položku s informací (např. číselnou) o právě používaném prvku unionu:

typedef struct { int info;
                 un x;
               }

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: