BitoweCzęść NR.1Co to są indeksery poza tym, że nie ma takiego polskiego słowa w słowniku.

O indekserach można pomyśleć jako o małej tablicy, która działa w podobny sposób do właściwości. Przechowują one jednak grupę wartości. Gdy właściwość odnosi do jednego pola w klasie, indeksery hermetyzują i odnoszą się do całej grupy wartości. Kod, który wyraża indekser jest podobny do stylu użycia tablicy.

Najlepszym sposobem na zrozumienie jak one działają jest pokazanie przykładu. Na początku pokażę rozwiązania, które ich nie używają ,abyś lepiej zrozumiał po co one są.

Problem dotyczy liczb całkowitych a mówiąc bardziej dokładnie typu int.

Indeksery. Przykład bez ich użycia

Normalnie używasz typu int  do przechowywania liczby całkowitej. Wewnętrznie typ int   przetrzymuje wartość w sekwencji 32 bitów, gdzie każdy bit ma wartość 0 albo 1. Zazwyczaj nas nie interesuje jaką reprezentacje wewnętrzną mają wartości liczby całkowitej.

Czasami programiści używają typu int do innych celów.

Niektóre programy używają int do ustawienia binarnych flag .Program manipuluje każdym oddzielnym bitem znajdującym się w wewnątrz int.

Dla programistów języka C nie jest to niczym nowym.

Stare programy używał typu int aby zaoszczędzić na pamięci. Stare programy musiały przechowywać złożone informacje w komputerze, w którym pamięć wynosiła kilka kilobajtów, a nie gigabajtów. Pojedynczy int trzymał w sobie 32 bity, a każdy z nich mógł być ustawiony na 1 albo na 0. W niektórych przypadkach wartość 1 symbolizowała prawdę ,a 0 symbolizowało fałsz. W ten sposób typ int mógłby być uznany za kontener grupy wartości logicznych.

C# udostępnia zbiór operatorów, które mają dostęp i manipulują pojedynczymi bitami w typie int.

  • Operator NOT ( ~ ):Jest to operacja jedno argumentowana, która odwraca wartości bitowe. Jedynka staje się zerem ,a zero staje się jedynką.
  • Operator przesunięcia w lewo ( << ):Ta operacja dwuargumentowa dokonuje przesunięcia w lewo. Przykładowo liczba 15 ma następujące wyrażenie 8 bitowe (00001111) przesuwając ją o dwie wartości w lewo wyrażeniem 15 << 2  zmienię wartość na (00111100) czyli na liczbę 60. Wyrażenia najbardziej na lewo są odrzucane ,a nowe zera pojawiają po prawej stronie. Istnieje podobny operator tylko działa on w drugim kierunku (>>)
  • Operator ( | ) OR: Kolejna operacja dwuargumentowa, która tym razem wykonuje operacje bitową OR. Zwraca ona bit 0 jeśli bity operandów “A” i “B” też mają zero w przeciwnym wypadku operacja ta zwraca jeden. Porównywanie bitowe operandów oczywiście dokonuje się w odpowiednich pozycjach bitowych. Przykładowo operacja 15 | 16  zwróci liczbę 31 ponieważ operacja bitowa “lub” na 00001111 i 00010000 zwróci 00011111. W wpisie o flagowaniu typów wyliczeniowych uprościłem opis tej operacji do dodawania ,ale nie jest to do końca prawda. W końcu jedynka pojawia się tam gdzie jej wcześniej nie było.
  • Operator ( & ) AND: Ten operator dokonuje operacji AND w podobnym stylu do operacji OR. Zwrócić on tylko 1 gdy obie wartości mają też jeden w innym wypadku jest zero.
  • Operator ( ^ ) XOR: Ten operator wykonuje operacje bitową "alternatywy wykluczającej" się. Operacja ta zwróci jeden gdy każdy z dwóch operandów ma różne wartości bitowe ,ale nie takie same. Więc operacja 15 ^ 16 zwróci 31 ponieważ 00001111 ^ 00010000 to 00011111.

Możesz używać tych operatorów wspólnie do ustalania wartości indywidualnych bitów w int.Przykładowo możesz wykonać zbiór następujących operacji.

int liczbaZBitów = (127 & (1 << 6));

Wyjaśnię co otrzymamy w wyniku takiej operacji. Liczba 1 ma wartość bitową 0000001 (wiem ,że int ma 32 bity ,ale oszczędzę sobie pisanie dodatkowych zer) operacja << przesuwa wartość bitową w lewo o sześć miejsc. Wynik tej operacji to 01000000, czyli liczba 64. Potem wykonuje się operacja AND pomiędzy liczbą 127 czyli bitami 00111111 ,a bitami z liczby 64. Wynikiem tej operacji jest liczba 64 ponieważ wszystkie pozostała bity zmieniły się w zero w wyniku operacji AND.

Podobnie jak w operatorach arytmetycznych (+=,-= *= ). Mamy skrótowe oznaczenia jak &= i |=

liczbaZBitów &= ~(1 << 7);//też 64 
liczbaZBitów = (liczbaZBitów & (~(1 << 7)));//to samo 
liczbaZBitów |= (1 << 7);//192 = 64 + 128 
liczbaZBitów = (liczbaZBitów | (1 << 7));//to samo 

Jak widzisz te operacje wymagają dużo pracy i nie są proste do zrozumienia.

Chociaż te operacje są przydatne przy wielowartościowych typach wyliczeniowych, o których pisałem tutaj.

Dlatego w następnym wpisie przedstawię jak wygląda rozwiązanie tego problemu pod znakiem indekserów.