Radek Chalupa - vývoj software

Hlavní stránka

Články

Vývoj software

Školení a konzultace

Webdesign

Externí spolupráce

Software

Knihy

Kontakt


Stručný úvod do bitových operací - masky, příznaky a posun

28.7.2004

Některé učebnice či osnovy kurzů jazyka C++ bohužel opomíjejí základy, tj. jazyk C. Dokonce se lze setkat i s názorem že při studiu jazyka C++ je nejlépe zapomenout na to co (někteří z té "staré školy") znají z jazyka C. Jedním z nepříjemných efektů tohotopřístupu může být větší či menší nejasnost v bitových operacích a bitovém maskování. Pokud programujete Win32 aplikace (ať již v čistém API nebo s knihovnou jako ATL či MFC) narazíte dříve či později (spíše dříve:-)) na toto téma. Jako příklad stačí uvést funkci CreateWindow, ve které například parametr určující styl okna je typu DWORD (32-bitové číslo) a jednotlivé vlastnosti (mající "hodnotu" ano/ne) jsou v tomto parametru zadávány jako bitové příznaky. Setkáte se pak s tím že tento parametr je zadán takovýmto výrazem:

WS_OVERLAPPEED | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS.

Hodnoty WS_xxxx jsou definovány v hlavičkovém souboru windows.h (resp. jestli se nepletu tak ve windef.h, který je do něj vložen - ale tozde vůbec není podstatné) jako čísla, která mají tu vlastnost že v jejich dvojkovém vyjádření obsahují pouze jednu jedničku. Jsou to tedy mocniny čísla 2, tj. základu dvojkové soustavy. Toto platí samozřejmě s výjimkou hodnot, které jsou už samy definovány jako kombinace těch zákaldních příznaků. Ostatně stačí se podívat například na deklaraci hodnoty WS_OVERLAPPEDWINDOW, která je poskládána z více samostaných hodnot WS_xxx.

Ukažme si ale konkrétní příklad, kde budou všechny použité příznaky opravdu bitové (s jednou jedničkou). Řekněme že budeme mít vytvářet nějaký objekt pomocí funkce s jedním parametrem, ve kterém budeme chtíz zadat 4 vlastnosti (A, B, C a D), které budou mít hodnotu ano/ne. tj. vlastnost buď bude nebo nebude v objektu zahrnuta.

Definice hodnot příznaků

Nejprve si nadefinujeme tyto příznaky vlastností například takto:

#define VLASTNOST_A    0x00000001
#define VLASTNOST_B    0x00000002
#define VLASTNOST_C    0x00000004
#define VLASTNOST_D    0x00000008

Nyní musíme umět nejprve 2 zákaldní věci: jednak složit z jednotlivých příznaků požadovaný parametr a naopak ze zadaného parametru zjistit, zda obsahuje ten který příznak (vlastnost).

Sestavení parametru z jednotlivých příznaků

Sestavení parametru je jednoduché. Použijeme operátor | mezi jednotlivými přízkanky, tj. např:

DWORD dwParametr = VLASTNOST_A | VLASTNOST_D;

Jak je tato operace realizována? Nejlépe si to představíte tak že napíšete pod sebe obě čísla v dvojkovém vyjádření a ve výsledku budou jedničky na tom místě, kde bude alespoň jedna jednička v některém z čísel, které takto "skládáme". V našem případě tedy dostaneme ve dvojkovém vyjádření hodnotu 1001.

Zjištění přítomnosto příznaku v zadané hodnotě

Potřebujeme-li naopak otestovat zda v zadaném čísle je obsažen daný příznak (obecně samozřejmě může jít i o příznak tvořený kombinací jednobitových příznaků), napíšeme pod sebe dvojkové vyjádření čísla a testovaného příznaku a ve výsledku bude jednička na tom místě, na kterém obě čísla zároveň obsahují jedničku. Dostaneme-li nenulový výsledek (tj. číslo obsahující alespoň jednu jedničku) znamená to že číslo (příznak) je v daném parametru (bitově) obsaženu. V jazyce C/C++ k této operaci použijeme operátor &. Ukážeme si to na příkladu výše zmíněnné funkce vytvářející objekt na základě zadaných vlastností.

void VytvoritObjekt(DWORD dwParametr)
{
  if ( dwParametr & VLASTNOST_A )
  {
    // kód který použije vlastnost A;
  }
  if ( dwParametr & VLASTNOST_B )
  {
    // kód který použije vlastnost B;
  }
  if ( dwParametr & VLASTNOST_C )
  {
    // kód který použije vlastnost C;
  }
  if ( dwParametr & VLASTNOST_D )
  {
    // kód který použije vlastnost D;
  }
}

Bitový posun

Další záležitostí na kterou při programováníá narazíte (i když asi méně často než na bitové příznaky) je bitový posun. K této operaci slouží 2 operátory:

Konkrétní příklad zápisu může vypadat třeba takto

x = lParam >> 16;

Co to znamená konkrétně? Můžete si to představit tak, že se všechny dvojkové číslice dvojkového zápisu čísla  posunou o 16 pozic vpravo. Ty číslice které se dostanou mimo rozsah jsou "vyhozeny" a vzniklé místo zleva se doplní nulami. U posunu vlevo je tomu právě naopak.

Když se vrátíme k výše uvedenému příkladu, někteří pravděpodobně vědí že realizuje zjištění hodnoty horního WORDu (16-bitové hodnoty) z daného 32-bitového parametru, tedy přímý zápis mnohým známého makra HIWORD.

Sdílet

  Copyright © 2010 Radek Chalupa || tel. 739 219 991Kontakt | Poslat e-mailÚvod