Co to jest maskowanie bitów?

191

Jestem całkiem nowy w programowaniu w C i napotkałem maskowanie bitów. Czy ktoś może mi wyjaśnić ogólną koncepcję i funkcję maskowania bitów? Przykłady są bardzo cenione.

Mr.Z
źródło
1
Czy rozumiesz operatory bitowe, takie jak & | ^ itp. i logika boolowska w ogóle? Wymaga tego każde wyjaśnienie operacji maski.
Paul R
1
Tak, rozumiem operatory bitowe i logikę logiczną
Mr.Z
2
Wiem, że linki nie powinny być publikowane, ale wikipedia wyjaśnienie jest wielki: en.wikipedia.org/wiki/Mask_(computing)
pevik
2
@pevik jest w porządku, aby opublikować link, ale z pewnym opisem, aby jeśli link kiedyś umrze, post nadal będzie mógł odpowiadać. również link nie powinien służyć wyłącznie celom promocyjnym.
Dexter,

Odpowiedzi:

245

Maska określa, które bity chcesz zachować, a które bity chcesz wyczyścić.

Maskowanie to czynność nakładania maski na wartość. Dokonuje się tego poprzez:

  • Bitowe ANDowanie w celu wyodrębnienia podzbioru bitów wartości
  • Bitowe ORowanie w celu ustawienia podzbioru bitów wartości
  • Bitowe XORing w celu przełączania podzbioru bitów wartości

Poniżej znajduje się przykład wyodrębnienia podzbioru bitów z wartości:

Mask:   00001111b
Value:  01010101b

Zastosowanie maski do wartości oznacza, że ​​chcemy wyczyścić pierwsze (wyższe) 4 bity i zachować ostatnie (niższe) 4 bity. W ten sposób wyodrębniliśmy dolne 4 bity. Wynik to:

Mask:   00001111b
Value:  01010101b
Result: 00000101b

Maskowanie jest realizowane za pomocą AND, więc w C otrzymujemy:

uint8_t stuff(...) {
  uint8_t mask = 0x0f;   // 00001111b
  uint8_t value = 0x55;  // 01010101b
  return mask & value;
}

Oto dość powszechny przypadek użycia: Wyodrębnianie pojedynczych bajtów z większego słowa. Definiujemy bity wysokiego rzędu w słowie jako pierwszy bajt. Używamy do tego dwóch operatorów &i >>(przesuń w prawo). W ten sposób możemy wyodrębnić cztery bajty z 32-bitowej liczby całkowitej:

void more_stuff(uint32_t value) {             // Example value: 0x01020304
    uint32_t byte1 = (value >> 24);           // 0x01020304 >> 24 is 0x01 so
                                              // no masking is necessary
    uint32_t byte2 = (value >> 16) & 0xff;    // 0x01020304 >> 16 is 0x0102 so
                                              // we must mask to get 0x02
    uint32_t byte3 = (value >> 8)  & 0xff;    // 0x01020304 >> 8 is 0x010203 so
                                              // we must mask to get 0x03
    uint32_t byte4 = value & 0xff;            // here we only mask, no shifting
                                              // is necessary
    ...
}

Zauważ, że możesz zmienić kolejność operatorów powyżej, możesz najpierw zrobić maskę, a potem przesunięcie. Wyniki są takie same, ale teraz musiałbyś użyć innej maski:

uint32_t byte3 = (value & 0xff00) >> 8;
użytkownik239558
źródło
5
Dobra odpowiedź, ale maskowanie można również zastosować do ustawiania lub przełączania określonych bitów za pomocą operacji OR lub XOR i odpowiedniej maski.
Paul R
@ user239558 dzięki za przykład i właściwą składnię. @ Paul R. Czy po prostu powiedziałbym mask AND value w przykładzie podanym przez user239558
Mr.Z
@ Mr.Z: w C, C ++ i językach pokrewnych byłbyś bitowym operatorem AND , który jest zapisany jako &.
Paul R
@ Mr.Z Na przykład: jasny jeden bajt uint32_t przez maskowanie zawartość stąd: #define MASK 0x000000FF .... my_uint32_t &= ~MASK.
Lundin
bdosłowne wskazać binarny nie jest obsługiwana przez wszystkie kompilatory, prawda?
Ungeheuer
76

Maskowanie oznacza zachowanie / zmianę / usunięcie żądanej części informacji. Pozwala zobaczyć operację maskowania obrazu; jak - ta operacja maskowania usuwa wszystko, co nie jest skórką -

wprowadź opis zdjęcia tutaj

W tym przykładzie wykonujemy operację AND . Istnieją również inne operatory maskowania - OR , XOR .


Maskowanie bitów oznacza nakładanie maski na bity. Oto maskowanie bitów za pomocą AND -

     1 1 1 0 1 1 0 1   [input]
(&)  0 0 1 1 1 1 0 0    [mask]
------------------------------
     0 0 1 0 1 1 0 0  [output]

1Pozostają więc tylko 4 środkowe bity (ponieważ te bity są w tej masce).

Zobaczmy to dzięki XOR -

     1 1 1 0 1 1 0 1   [input]
(^)  0 0 1 1 1 1 0 0    [mask]
------------------------------
     1 1 0 1 0 0 0 1  [output]

Teraz środkowe 4 bity są odwrócone ( 1stały się 0, 0stały się 1).


Tak więc za pomocą maski bitowej możemy uzyskać dostęp do poszczególnych bitów [ przykłady ]. Czasami tę technikę można również wykorzystać do poprawy wydajności. Weź to na przykład

bool isOdd(int i) {
    return i%2;
}

Ta funkcja informuje, czy liczba całkowita jest nieparzysta / parzysta. Możemy osiągnąć ten sam wynik z większą wydajnością za pomocą maski bitowej

bool isOdd(int i) {
    return i&1;
}

Krótkie wyjaśnienie : Jeżeli najmniej znaczący bit liczby binarnej 1jest nieparzysty; bo 0tak będzie. Tak, wykonując I z 1usuwamy wszystkie inne kawałki z wyjątkiem najmniej znaczącego bitu tzn:

     55  ->  0 0 1 1 0 1 1 1   [input]
(&)   1  ->  0 0 0 0 0 0 0 1    [mask]
---------------------------------------
      1  <-  0 0 0 0 0 0 0 1  [output]
Minhas Kamal
źródło
1
Ponadto, aby przekonwertować liczbę całkowitą na liczbę nieparzystą. jeśli jest to liczba parzysta: i = i | 1. Jest to przydatne, gdy próbujemy wygenerować sekwencję taką jak 1, 3, 5, ..., 2, 4, 6, ...
Harshit Sharma
Możesz także użyć następującej operacji, aby znaleźć liczbę z najmniej znaczącym bitem z liczby całkowitej: lsb = i & -i
Harshit Sharma