Що таке бітове маскування?


191

Я досить новачок у програмуванні на С, і мені траплялося бітове маскування. Чи може хтось пояснити мені загальну концепцію та функцію біт-маскування? Приклади високо цінуються.


1
Чи розумієте ви побитові оператори, такі як & | ^ тощо та логічна логіка взагалі? Будь-яке пояснення операцій з маскою вимагатиме цього.
Павло Р

1
Так, я розумію розрядні оператори та булеву логіку
Mr.Z

2
Я знаю, що посилання не слід розміщувати, але пояснення у wikipedia чудово: en.wikipedia.org/wiki/Mask_(computing)
pevik

2
@pevik це нормально, щоб опублікувати посилання, але з деяким описом, так що якщо посилання вмирає коли-небудь, публікація все ще може служити своїй меті відповіді. також посилання не повинно бути лише для рекламних цілей.
Декстер

Відповіді:


245

Маска визначає, які біти потрібно зберегти та які біти потрібно очистити.

Маскування - це акт нанесення маски на значення. Це здійснюється завдяки:

  • Побітове ANDing для вилучення підмножини бітів у значенні
  • Побітове АБО для встановлення підмножини бітів у значенні
  • Побітове XORing, щоб перемикати підмножину бітів у значенні

Нижче наведено приклад вилучення підмножини бітів у значенні:

Mask:   00001111b
Value:  01010101b

Застосування маски до значення означає, що ми хочемо очистити перший (вищий) 4 біт, а останній (нижній) 4 біт. Таким чином ми витягли нижні 4 біти. Результат:

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

Маскування реалізується за допомогою AND, тому в C ми отримуємо:

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

Ось досить поширений випадок використання: Вилучення окремих байтів із більшого слова. Ми визначаємо біти високого порядку в слові як перший байт. Для цього ми використовуємо два оператори &, і >>(зсув праворуч). Ось як можна дістати чотири байти з 32-бітного цілого числа:

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
    ...
}

Зауважте, що ви можете змінити порядок операторів вище, ви можете спершу зробити маску, а потім зсув. Результати однакові, але тепер вам доведеться використовувати іншу маску:

uint32_t byte3 = (value & 0xff00) >> 8;

5
Хороша відповідь, але маскування може також застосовуватися для встановлення або перемикання конкретних бітів за допомогою операцій АБО чи XOR та відповідної маски.
Пол Р

@ user239558 дякую за приклад та належний синтаксис. @ Пол Р. Я просто сказав би маску І значення у прикладі, наданому користувачем239558
Mr.Z

@ Mr.Z: на C, C ++ та суміжних мовах ви отримаєте побітовий оператор AND , який записується як &.
Пол Р

@ Mr.Z Наприклад: ясно один байт uint32_t шляхом маскування вмісту геть: #define MASK 0x000000FF .... my_uint32_t &= ~MASK.
Лундін

bвказати двійковий літерал не підтримує всіма компіляторами, правильно?
Ungeheuer

76

Маскування означає зберігати / змінювати / видаляти бажану частину інформації. Подивимось операцію маскування зображень; як - ця маскувальна операція видаляє будь-яку річ, яка не є шкірою-

введіть тут опис зображення

Ми робимо І операцію в цьому прикладі. Є й інші оператори маскування - АБО , XOR .


Біт-маскування означає накладення маски на біти. Ось трохи маскування з 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]

Отже, 1залишаються лише середні 4 біти (оскільки ці біти є в цій масці).

Давайте побачимо це за допомогою 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]

Тепер середні 4 біти перевернуті ( 1стали 0, 0стали 1).


Отже, використовуючи біт-маску, ми можемо отримати доступ до окремих бітів [ приклади ]. Іноді цей прийом може бути використаний і для підвищення продуктивності. Візьмемо це для прикладу-

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

Ця функція повідомляє, чи ціле число непарне / парне. Ми можемо досягти того ж результату за рахунок більшої ефективності, використовуючи біт-маску-

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

Коротке пояснення : якщо найменший значущий біт двійкового числа, 1то він непарний; бо 0воно буде рівним. Таким чином, роблячи і з 1ми видаляємо всі інші біти для найменшого значущого біта тобто за винятком:

     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]

1
Також для перетворення цілого числа в непарне немає. якщо це парне число: i = i | 1. Це стане в нагоді, коли ми намагаємося створити таку послідовність, як 1, 3, 5, ..., 2, 4, 6, ...
Harshit Sharma

Ви також можете скористатися такою операцією, щоб знайти число з найменш значущим бітом з цілого числа: lsb = i & -i
Harshit Sharma
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.