Перейти до вмісту

Маскування (програмування)

Матеріал з Вікіпедії — вільної енциклопедії.

Маскувáння (англ. mask, masking) — в інформатиці — спосіб обробки даних на бітовому рівні, для одержання значення якогось біта або набору бітів з числа, слова або байта. Маскування виконують з використанням логічних операцій та потрібним набором бітів — маскою.

Маска або бітова маска — дані, використовувані для побітових операцій, зокрема в бітовому полі. Використовуючи маску, кілька бітів у байті, півбайті, слові тощо можна ввімкнути або вимкнути, або інвертувати з увімкнення на вимкнення (або навпаки) за допомогою однієї побітової операції. Також маскування використовують для предикації[en] в обробці векторів, де бітова маска забезпечує вибір того, виконується операція з елементами вектора (біт маски ввімкнено), чи ні (біт маски вимкнено).

Назва походить від аналогії з простим шифруванням, коли маска з отворами, накладена на беззмістовний текст, відкриває лише потрібні букви.

Типові випадки маскування

[ред. | ред. код]

Встановлення бітів у 1

[ред. | ред. код]

Щоб увімкнути певні біти, можна використати порозрядну операцію АБО (OR), завдяки тому, що для окремого біта Y Y OR 1 = 1 і Y OR 0 = Y. Тому, щоб забезпечити стан біта 1, слід виконати OR з 1. Щоб залишити біт без змін, OR виконуємо з 0.

Приклад: вимкнення старшого нібла (біти 4, 5, 6, 7), але залишення молодшого нібла (біти 0, 1, 2, 3) без змін.

   10010101 10100101
OR 11110000 11110000
 = 11110101 11110101

Встановлення бітів у 0

[ред. | ред. код]

Частіше на практиці біти «вимикають» (або маскують у 0). Якщо до біта застосувати операцію І (AND) з 0, результат завжди дорівнює 0, тобто Y AND 0 = 0. Щоб залишити інші біти незміненими, над ними слід виконати AND з 1, оскільки Y AND 1 = Y

Приклад: маскування старшого нібла (біти 4, 5, 6, 7), залишаючи молодший нібл (біти 0, 1, 2, 3) без змін.

    10010101 10100101
AND 00001111 00001111
 =  00000101 00000101

Запит статусу біта

[ред. | ред. код]

За допомогою бітової маски легко перевірити стан окремого біта. Для цього всі інші біти вимикаємо за допомогою порозрядного AND як описано вище, і значення порівнюємо з 0. Якщо воно дорівнює 0, то біт був вимкнений, але якщо воно відмінне від 0, то біт був увімкненим. Зручно, що немає необхідності з'ясовувати, яке насправді значення отримано, достатньо того, що воно не дорівнює 0.

Приклад: запит статусу 4-го біта

    10011101 10010101
AND 00001000 00001000
 =  00001000 00000000

Перемикання значень бітів

[ред. | ред. код]

Іноді, незалежно від значення біта, його потрібно зробити протилежним до поточного (інвертувати). Цього можна досягти за допомогою операції XOR (виключне АБО). XOR повертає 1 тоді й лише тоді, коли непарна кількість бітів-операндів дорівнює 1. Отже, якщо два відповідні біти дорівнюють 1, результатом буде 0, але якщо лише один із них дорівнює 1, результатом буде 1. Тому інверсію значень бітів виконують за допомогою XOR з 1. Якщо початковий біт був 1, отримаємо 1 XOR 1 = 0. Якщо початковий біт був 0, отримаємо 0 XOR 1 = 1. Також зауважте, що маскування за допомогою XOR безпечне для бітів, тобто воно не вплине на незамасковані біти, тому що Y XOR 0 = Y, як і OR.

Приклад: перемикання значень бітів

    10011101 10010101
XOR 00001111 11111111
 =  10010010 01101010

Щоб записати довільні 1 і 0 до підмножини бітів, спочатку запишіть 0 до цієї підмножини, а потім встановіть старші біти:

  register = (register & ~bitmask) | value;

Використання бітових масок

[ред. | ред. код]
У фокусі зі вгадуванням того, на яких картках надруковано число, використано біти двійкового подання числа. У файлі SVG клацніть на картці, щоб перемкнути її.

Аргументи функцій

[ред. | ред. код]

У мовах програмування, таких як C, бітові поля — це корисний спосіб передавання набору іменованих булівських аргументів у функцію. Наприклад, у графічному API OpenGL є команда glClear() яка очищає екран або інші буфери. Вона може очистити до чотирьох буферів (буфер кольору, глибини, накопичення та шаблону), тому автори API могли мати чотири аргументи. Але тоді виклик функції виглядав би так

що не дуже наочно. Натомість є чотири визначені біти поля: GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_ACCUM_BUFFER_BIT і GL_STENCIL_BUFFER_BIT, а glClear() оголошено як

 void glClear(GLbitfield bits);

Тоді виклик функції виглядає так

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Завдяки цьому, функція, яка приймає таке бітове поле, може використовувати побітове AND для доступу до окремих бітів. Наприклад, реалізація glClear() може бути такою:

void glClear(GLbitfield bits) {
  if ((bits & GL_COLOR_BUFFER_BIT) != 0) {
    // Очистити буфер кольору.
  }
  if ((bits & GL_DEPTH_BUFFER_BIT) != 0) {
    // Очистити буфер глибини.
  }
  if ((bits & GL_ACCUM_BUFFER_BIT) != 0) {
    // Очистити буфер накопичення.
  }
  if ((bits & GL_STENCIL_BUFFER_BIT) != 0) {
    // Очистити буфер шаблону.
  }
}

Перевага цього підходу полягає в тому, що обсяг аргументів функції зменшується. Оскільки найменший обсяг даних становить один байт, розділення параметрів на окремі аргументи призвело б до втрати семи бітів на кожному значенні, а отже до збільшення обсягу даних у стеку. Натомість функції зазвичай приймають одне або кілька 32-розрядних цілих чисел, кожне з яких містить до 32 бітових параметрів. Попри елегантність, у найпростішій реалізації це рішення не є типобезпечним. GLbitfield просто визначено як unsigned int, тому компілятор дозволив би безглуздий виклик glClear(42) або навіть glClear(GL_POINTS). У C++ альтернативою було б створити бібліотечний клас для інкапсуляції набору аргументів, які може приймати glClear.

Інверсні маски

[ред. | ред. код]

Маски використовують із IP-адресами в IP ACL (списках контролю доступу), щоб визначити, що має бути дозволено, а що заборонено. Маски для налаштування IP-адрес на інтерфейсах починаються з 255 і мають великі значення зліва: наприклад, IP-адреса 203.0.113.129 з маскою 255.255.255.224. Маски для IP ACL навпаки: наприклад, маска 0.0.0.255. Це іноді називають інверсною маскою або маскою підстановки[en]. Коли значення маски розглядається як двійкове (з 0 і 1), воно визначає, які біти адреси слід враховувати при обробці трафіку. 0 вказує на те, що необхідно враховувати біт адреси (точна відповідність); 1 в масці означає «байдуже». Для пояснення концепції розгляньмо приклад.

Приклад маски:

мережева адреса (трафік, який потрібно обробити): 192.0.2.0
маска: 0.0.0.255
мережева адреса (двійкова): 11000000.00000000.00000010.00000000
маска (двійкова): 00000000.00000000.00000000.11111111

Виходячи з двійкової маски, можна побачити, що перші три набори (октети) мають точно відповідати заданій двійковій мережевій адресі (11000000.00000000.00000010). Останній набір чисел складається з «байдуже» (.11111111). Отже, увесь трафік, який починається з «192.0.2.», збігається, оскільки останній октет — «байдуже». Тому з цією маскою обробляються мережеві адреси від 192.0.2.1 до 192.0.2.255 (192.0.2.x).

Якщо звичайну маску відняти від 255.255.255.255, то отримаємо інверсну маску ACL. У цьому прикладі визначено інверсну маску для мережевої адреси 198.51.100.0 зі звичайною маскою 255.255.255.0:

255.255.255.255 — 255.255.255.0 (звичайна маска) = 0.0.0.255 (інверсна маска)

Еквіваленти ACL:

  • Джерело/підстановка джерела 0.0.0.0/255.255.255.255 означає «будь-яка».
  • Джерело/підстановка 198.51.100.2/0.0.0.0 означає те саме, що й «хост 198.51.100.2».

Маскування зображень

[ред. | ред. код]
Растрові спрайти (ліворуч) і маски (праворуч)

У комп'ютерній графіці для зображення, призначеного для розміщення на тлі, прозорі ділянки можна вказати за допомогою двійкової маски.[1] В такому разі для кожного із зображень насправді існує два растрові зображення: фактичне зображення, у якому невикористані ділянки мають значення в пікселях із усіма бітами, встановленими на 0, і додаткова маска, в якій ділянкам зображення відповідають значення 0 усіх бітів у пікселях, а прозорим ділянкам — значення 1. На малюнку праворуч чорні пікселі мають усі нульові біти, а білі пікселі — всі одиничні біти.

Під час виконання[en], щоб розмістити зображення на екрані поверх тла, програма спочатку маскує біти пікселя екрана в потрібних координатах за допомогою маски зображення та бітової операції І. Це зберігає пікселі тла прозорих ділянок, а біти пікселів, які має закрити зображення, скидає на нуль.

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

Ця техніка використовується для малювання курсорів вказівних пристроїв, у типових двовимірних відеоіграх для персонажів, куль тощо (спрайтів), для піктограм графічного інтерфейсу користувача, а також для створення заголовків відео та інших програм для змішування зображень. Швидший спосіб — просто перезаписати пікселі тла пікселями переднього плану, якщо їх альфа=1

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

Геш-таблиці

[ред. | ред. код]

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

Приклад обох підходів на C:

#include <stdint.h>
#include <string.h>

int main(void) {
  const uint32_t NUM_BUCKETS = 0xFFFFFFFF; // 2^32 - 1
  const uint32_t MAX_RECORDS = 1<<10; // 2^10
  const uint32_t HASH_BITMASK = 0x3FF; // (2^10)-1

  char **token_array = NULL;
  // Опрацювання розміщення в пам'яті token_array…

  char token[] = "some hashable value";
  uint32_t hashed_token = hash_function(token, strlen(token), NUM_BUCKETS);

  // Використовуємо остачу
  size_t index = hashed_token % MAX_RECORDS;

  // АБО

  // Використовуємо бітову маску
  size_t index = hashed_token & HASH_BITMASK;

  *(token_array+index) = token;

  // Вивільняємо пам'ять token_array …
  return 0;
}

Див. також

[ред. | ред. код]

Примітки

[ред. | ред. код]
  1. Mask R-CNN with OpenCV. PyImageSearch (амер.). 19 листопада 2018. Процитовано 5 квітня 2020.