Učíme se C (25. díl) - Bitové operátory a bitové pole - 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 (25. díl) - Bitové operátory a bitové pole

28. května 2001, 00.00 | Dnes o tom, jaké jazyk C nabízí operátory a datové struktury pro
práci s bity, k čemu tyto operátory slouží a jak se používají.

Bitové operátory a bitové pole

Protože jazyk C je oproti jiným vyšším jazykům zaměřen na přeci jen poněkud nižší úroveň, nabízí programátorům i operátory, pomocí kterých mohou nepřímo pracovat i s jednotlivými bity.

V následujícím textu budu předpokládat znalost některých základních booleových funkcí jako je AND, OR apod.

bitový součin - &

První z operátorů, na které se dnes podíváme, je operátor bitového součinu. Tento operátor provede logickou operaci AND mezi všemi bity svých operandů a takto vzniklá hodnota bude i výsledkem celé operace. Nejlépe si to demonstrujeme rovnou na příkladu:

77 & 198

Výslednou hodnotou tohoto výrazu bude číslo 68. Pro lepší pochopení se podívejme přímo na binární zápisy těchto hodnot.

77   01001101
198  11000110
68   01000100

Operandy operátoru binárního součinu mohou být pouze výrazy celočíselného typu, není tedy možné provádět bitový součin s hodnotami typu float, double ani long double.

Jedno z možných použití operátoru & si můžeme demonstrovat na příkladu, ve kterém si zkusíme vytvořit jednoduché makro, které zjistí, zda je jemu předaný argument lichý či sudý.

#define liche(x) (1 & (x))

bitový součet - |

Existuje-li v C operátor bitového součinu, jistě bude implementována i operace bitového součtu. Tu provádí operátor |, který má, až na to, že s bity provádí operaci OR, stejné vlastnosti jako operátor &. V příkladu použijeme stejné hodnoty jako minule.

77 | 198 == 207

77      01001101
198     11000110
207     11001111

bitový exklusivní součet - ^

Oba předchozí operátory doplňuje ještě jeden podobný, který s jednotlivými bity svých operandů provádí operaci XOR.

77 ^ 198 == 139

77      01001101
198     11000110
139     10001011

bitová negace - ~

Na rozdíl od předchozích operátorů je bitová negace unárním operátorem, tedy má pouze jeden operand. Ten musí být, stejně jako v předchozích případech, celočíselného typu. Při provádění operace jsou postupně všechny jeho bity negovány a takto získaná hodnota je výsledkem použití operátoru. V následujícím příkladu uvažujeme typy unsigned char. V případě použití typu signed by ještě hrál roli negovaný znaménkový bit.

~77 == 178

77      01001101
178     10110010

Protože jsou negovány všechny bity čísla, včetně počátečních nul, znamená to, že pro operandy se stejnou hodnotou, ale různým typem (char, short, int, long int), bude výsledná hodnota různá.

bitový posun doleva - <<

Tímto operátorem jednoduše provedeme posun všech bitů levého operandu o určitý počet míst, který udává hodnota pravého operandu. Při posunu se bity nejvíce nalevo ztrácejí a zleva jsou uvolněná místa doplněna nulami. Následující příkaz vrátí o dvě místa bitově posunutou hodnotu čísla 45.

45 << 2;

před posunem (hodnota 45) 00101101
po posunu (hodnota 180, výsledek celého výrazu) 10110100

Bitový posun doleva se často používá k provádění násobení mocninami dvou. Tento způsob je totiž znatelně rychlejší než normální násobení. Platí, že x << n == x*2n. Schopnější překladače dnes již samy nahrazují (je li to možné) obyčejné násobení bitovým posunem.

bitový posun doprava - >>

Komplementární operací k bitovému posunu doleva je bitový posun doprava. V tomto případě se bity zprava ztrácí a zleva jsou doplňovány nulou u neznaménkových typů, nebo znaménkovým bitem u typů znaménkových, což je ale implementačně závislé. Stejně jako se dal bitový posun doleva použít k násobení, lze zase bitový posun doprava použít k celočíselnému dělení mocninami dvou. x >> n == x/2n

48 >> 4 == 3

přiřazovací bitové operátory

Jak je v C zvykem, i k bitovým operátorům existují jejich verze kombinující v sobě přiřazení, a proto můžeme některé zápisy zkrátit pomocí následujících operátorů:

&=
|=
^=
<<=
>>=

bitové pole

Bitové pole je datový objekt podobný typu struct, kde ale lze pro každou položku definovat i její velikost v bitech, což lze využít například potřebujeme-li šetřit pamětí, nicméně je nutné si uvědomit, že celková velikost bude vždy zarovnána na násobek sizeof(int). Typy položek bitového pole jsou omezeny pouze na typ int (signed i unsigned) a velikost každé z nich nesmí překročit počet bitů alokovaných typem int.

Deklarace bitového pole je v podstatě totožná s deklarací obyčejné struktury, pouze přibude informace o počtu bitů obsazených jednotlivými jeho položkami. Ani přístup k položkám nebude v případě bitového pole odlišný od způsobů používaných při práci s typem struct. Ukažme si to na následujícím příkladu:

#define MUZ 0;
#define ZENA 1;

//deklarace bitového pole
typedef struct { unsigned int pohlavi : 1;
                 unsigned int vaha : 8;
                 unsigned int vek : 7;
               } CLOVEK;

CLOVEK osoba1; //definice proměnné typu bitové pole

osoba1.pohlavi = MUZ;
osoba1.vaha = 79;
osoba1.vek = 25;

V příkladu použité bitové pole CLOVEK pro jednoduchost nepodporuje přílišnou dlouhověkost ani nadváhu. :)

Proměnná osoba1 bude v paměti uložena takto(směr ukládání je ovšem implementačně závislý):

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
pohlavi vaha vek

Při definování jednotlivých položek bitového pole je možné neuvést identifikátor položky. Taková položka pak nebude přístupná přes žádný identifikátor, pouze jí bude vyhrazeno příslušné místo. Např.

typedef struct { unsigned int pohlavi : 1;
                 unsigned int : 1;
                 unsigned int vaha : 8;
                 unsigned int vek : 7;
               } CLOVEK;

V případě, že by některá z položek přesahovala za hranici velikosti typu int, bude zarovnána na začátek této hranice. Pokud bychom uvažovali sizeof(int)==2, v příkladu výše by se to týkalo položky vek, která by o jeden bit překročila hranici velikosti typu int. Proto celá tato struktura zabírá 2*sizeof(int) místa. Zarovnání na další hranici int lze také vynutit přidáním položky nulové délky.

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: