W tej lekcji powiemy sobie o operacjach binarnych czyli bezpośrednio na bitach w bajcie. My patrząc na jakąś zmienną, np. na "int", patrzymy na nią jak na jakąś liczbę np. 123, ale w rzeczywistości jest to układ zer i jedynek. Każda zmienna to zera i jedynki i musimy mieć świadomość, że nie musimy traktować int'a jak liczby, ale jak 32 kolejne bity, w których możemy zapisać dwie wartości 0 lub 1. W tej lekcji pokażę jak sprawdzać i zmieniać pojedyncze bity w zmiennej.

Sprawdzenie bitu

Do manipulowania bitami używa się masek i odpowiednich operatorów. Zajmijmy się maską, jest to wartość, która pomoże nam osiągnąć zamierzony rezultat operacji binarnej, ciężko to wytłumaczyć, dlatego zastosowanie masek zobaczymy w konkretnych zastosowaniach.

Dobrze więc, przejdźmy do pierwszego przykładu. Mamy liczbę int(32 bitową) powiedzmy, że jej wartość poda użytkownik i chcemy sprawdzić w niej 20 bit. Do tej operacji będzie potrzebny nam operator & (iloczyn bitowy, ma ten sam znak co operator wyłuskania adresu, ale to inny operator), który porównuje wszystkie bity dwóch zmiennych i jeżeli bity na tych samych miejscach będą wynosiły po 1, to w wyniku będzie także 1, jeżeli nie w wyniku będzie bit 0. Spójrzmy na schemat:

00010110  01101001  11101101  00110111
                  &
01011011  00100010  11100011  11100101
          wynikowa zmienna:
00010010  00100000  00100011  00100101

Jak widzisz działanie tego operatora nie jest zbyt skomplikowane. Teraz wróćmy do naszego przykładu mamy w jakiejś liczbie(32 bitowej) sprawdzić 20 bit. Już wiadomo, że trzeba użyć operatora iloczynu bitowego &, jeszcze potrzeba nam maski. Jak już wcześniej powiedziałem maska to zmienna, której używamy, aby uzyskać dany rezultat, w naszym przypadku chcemy sprawdzić 20 bit, wszystkie inne bity są dla nas nie istotne, dlatego nasza maska na wszystkich bitach oprócz dwudziestego powinna mieć bity 0, a istotny jest dla nas bit 20, dlatego tam powinna mieć 1, czyli nasza maska do tej operacji powinna wyglądać tak:

00000000  00001000  00000000  00000000

Pamiętajmy, że bity liczymy od prawej strony, czyli ten najbardziej z prawej jest pierwszy. A ten z lewej ostatni, czyli 32 bit.

Teraz przeprowadźmy naszą operację sprawdzenia bitu w jakiejś liczbie:

00010110  01100001  11101101  00110111    (sprawdzana liczba)
                  &
00000000  00001000  00000000  00000000    (maska)
          wynikowa zmienna:
00000000  00000000  00000000  00000000    (wynik)

Jak widać, zawsze będą możliwe tylko dwa wyniki tej operacji, jeżeli bit 20 będzie zerowy, to wynikowa zmienna będzie miała wszystkie bity równe 0(wartość 0). Jeżeli 20 bit będzie nie zerowy(1), wtedy, zmienna wynikowa, będzie miała 20 bit równy 1, więc będzie równa naszej masce. W ten sposób możemy sprawdzić wartość jakiegoś bitu, oczywiście, aby sprawdzić wartość innego bitu, trzeba zmienić maskę, w której musimy podać sprawdzany bit jako 1, a resztę jako 0. Możliwe są sprawdzania większej ilości bitów, ale już dla dwóch sprawdzanych bitów, możliwe będą 4 wartości, dla 3 bitów, 9 możliwych wartości.

No to przejdźmy do kodzenia w C++. My nie będziemy bezpośrednio wypisywać bitów, ale będziemy podawać wartości liczbowe tych konfiguracji bitów. Teraz skąd mamy wiedzieć, jaka to liczba, która ma 20 miejscu bit 1, a reszta to bity 0. Z pomocą przychodzi nam windowsowski kalkulator, w którym możemy sobie skonwertować liczby z kodu binarnego do szesnastkowego czy dziesiątkowego.

#include <iostream>


using namespace std;

int main(int argc,char* argv[])
{
  unsigned int liczba;
//deklarujemy naszą liczbę(układ bitów) dla operacji bitowej

  cout<<
"Podaj liczbe do sprawdzenia w niej 20 bitu: "
;
  cin>>liczba;
  unsigned int wynik=liczba&
524288
;
//operacja bitowa, naszą maską jest 20 bit, czyli liczba 524288,
  //bo ta liczba 524288, ma binarną(w systemie dwójkowym) postać 10000000000000000000

  cout<<endl<<
"Bit 20 wynosi: "
;
  if(wynik) cout<<
"1"
; else cout<<
"0"
;
//jeżeli wynik wynosi wartość niezerową znaczy, że bit wynosi 1
  //w przeciwnym wypadku(wartość zerowa) bit musi wynosić 0

  cout<<endl;
  system(
"PAUSE"
);
  return
0
;
}


Ustawianie bitu

Zatem potrafimy już sprawdzać poszczególne bity w zmiennej, za pomocą maski. Tylko po co nam taka umiejętność? Otóż, dzięki temu możemy uczynić nasze programy bardziej oszczędnymi. Możemy zapisywać poszczególne dane jako pojedyncze bity w jednej zmiennej. Skoro możemy już odczytywać bity, przydałoby się móc je ustawiać. Do tego także przydadzą nam się maski i operator sumy bitowej.

No więc może najpierw poznajmy zasadę działania operatora sumy bitowej |. Ten operator w zmiennej wynikowej ustawia wartość bitu 1, jeżeli chociaż jedna z wartości bitu w obu zmiennych wynosi 1.

00010110  01101001  11101101  00110111
                  |
01011011  00100010  11100011  11100101
          wynikowa zmienna:
01011111  01101011  11101011  11110111

Teraz maska, więc tutaj jest tak samo, powiedzmy, że chcemy ustawić piąty bit na 1, w tym celu przygotowujemy maskę, w której piąty bit ma wartości 1, a reszta 0, przy czym łączymy te zmienne operatorem sumy bitowej. Wygląda to tak:

00010110  01100001  11101101  00100111    (ustawiana liczba)
                  |
00000000  00000000  00000000  00010000    (maska)
          wynikowa zmienna:
00010110  01100001  11101101  00110111    (wynik)

Tym sposobem, możemy ustawić każdy bit na 1, nic nie stoi na przeszkodzie, aby w masce ustawić kilka bitów na 1, dzięki czemu od razu kilka bitów zostanie ustawione na 1. Tutaj dla ścisłości powiem, że jeżeli wcześniej ustawiany bit miał wartość 1, to się po prostu nic nie stanie, zmienna wynikowa będzie miała taką samą postać jak ustawiana zmienna.

Praktyczne zastosowanie

W Windows API często używa się masek, nazywa się je także flagami. Często będziemy ustawiać różne parametry, łącząc ze sobą różne flagi, musimy mieć świadomość, że w ten sposób ustawiamy poszczególne bity w zmiennej, każdy bit może być inną opcją. Nie ma problemu, aby w swoim programie także, zrobić zmienną, która będzie zawierała konfigurację bitów, a każdy bit będzie oznaczał, że coś jest włączone lub nie.

Przykładowo, chcemy mieć w programie 5 opcji które, będziemy ustawiać w zmiennej "opcje". Pierwszy bit, będzie odpowiedzialny za wyświetlenie uśmieszku, drugi języka, trzeci procentów ;), czwarty zaś mówi nam czy ma być wyświetlone ^^, ostatni piąty bit będzie wyświetlał jakiś szlaczek. Sprawa prosta, jeżeli dany bit będzie wynosił 0 opcja będzie wyłączona, jeżeli 1 włączona. Do pięciu opcji wystarczy nam 5 bitów, więc musimy użyć zmiennej nie większej niż 8 bitów, czyli w C++ "unsigned char".

#include <iostream>


//nasze maski(liczby nazywamy wyrazami):

#define USMIESZEK 1
//liczba 1 ma postać binarną 00001 (1 bit ma 1, reszta 0)

#define JEZYCZEK 2
//liczba 2 ma postać binarną 00010 (2 bit ma 1, reszta 0)

#define PROCENTY 4
//liczba 4 ma postać binarną 00100 (3 bit ma 1, reszta 0)

#define UCIESZONY 8
//liczba 8 ma postać binarną 01000 (4 bit ma 1, reszta 0)

#define SZLACZEK 16
//liczba 16 ma postać binarną 10000 (5 bit ma 1, reszta 0)

//łatwo zauważyć, że kolejne bity to potęgi liczby 2,
//czyli np bit 20 to liczba 2 do potęgi 19


using namespace std;

int main(int argc,char* argv[])
{
  unsigned char opcje=
0
;
//wyzerujmy zmienną, czyli ustawmy wszystkie bity na 0
  //najpierw użytkownik skonfiguruje program

  char tekst1[]=
"Czy chcesz wyswietlic "
;
//standardowy tekst informujacy

  char tekst2[]=
"? Podaj t dla tak.\n"
;
//standardowy tekst informujący

  char a;
//zmienna przechowująca decyzję użytkownika

  cout<<tekst1<<
"usmieszek"
<<tekst2;
  cin>>a;
//użytkownik decyduje czy włączamy opcję

  if(a=='t') opcje|=USMIESZEK;
//jeżeli podał t, ustawimay bit UŚMIESZKU na 1
  //operacja opcje|=USMIESZEK to tak samo jakby napisać opcje=opcje|USMIESZEK

  cout<<tekst1<<
"jezyczek"
<<tekst2;
  cin>>a;
  if(a=='t') opcje|=JEZYCZEK;
  cout<<tekst1<<
"procenty"
<<tekst2;
  cin>>a;
  if(a=='t') opcje|=PROCENTY;
  cout<<tekst1<<
"ucieszony"
<<tekst2;
  cin>>a;
  if(a=='t') opcje|=UCIESZONY;
  cout<<tekst1<<
"szlaczek"
<<tekst2;
  cin>>a;
  if(a=='t') opcje|=SZLACZEK;
  
//po skonfigurowaniu programu w zminnej opcje, możemy przejść do wyświetlania wyników
  //będziemy sprawdzać bity w zmiennej opcje

  cout<<endl;
  if(opcje&USMIESZEK) cout<<
":D "
;
//sprawdzamy bit USMIESZEK

  if(opcje&JEZYCZEK) cout<<
":P "
;
//itd. reszta bitów

  if(opcje&PROCENTY) cout<<
"% "
;
  if(opcje&UCIESZONY) cout<<
"^^ "
;
  if(opcje&SZLACZEK) cout<<
"~"
;
  cout<<endl;
  system(
"PAUSE"
);
  return
0
;
}

Wejść na stronę:     Ilość osób online:
Prawa autorskie © 2008 crayze. Wszelkie prawa zastrzeżone.
crayze7@gmail.com