Бітове поле

Бітове поле - в програмуванні число, що займає деякий набір бітів, безпосередньо не адресується процесором. Наприклад: при 8-бітному байті перші два поля протоколу IP - версія і IHL - будуть бітовими полями. На машинах з 32-бітовим байтом всі поля IP-пакета (крім IP-адрес відправника і одержувача) будуть бітовими.

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

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


1. Операції над многобітовимі полями

Нехай в одному байті знаходяться три бітових поля: 1-бітові a і b, 2-бітове c і 4-бітове d, тобто x = a + b \ cdot 2 ^ 1 + c \ cdot 2 ^ 2 + d \ cdot 2 ^ 4 .

 [Старший біт] ddddccba [молодший біт] 

Наприклад: при a = 1, b = 0, c = 2 = 10 2, d = 5 = 0101 2 отримуємо x = 01011001 2 = 89.

1.1. Збірка одного числа з бітових полів

Двійкові комп'ютери зазвичай мають команди побітового зсуву, які дозволяють швидко множити на ступені двійки - 2, 4, 8 і т. д. Замість складання можна застосувати команду логічного "АБО". Таким чином, число x можна зібрати і по-іншому:

 x = (d << 3) | (c << 2) | (b << 1) | a 

1.2. Витяг бітового поля

Для витягання бітового поля потрібно провести дві операції:

  1. Помножити операцією логічного "І" число на бітову маску - число, у якого в відповідних розрядах одиниці, а в решті нулі.
  2. Провести побітовий зрушення вправо.

Тобто:

 c = (x & 00001100b) >> 2 

Або:

  1. Провести побітовий зрушення вправо.
  2. Помножити операцією логічного "І" число на бітову маску відповідної довжини.
 c = (x >> 2) & 00000011b 

Для молодшого поля побітовий зрушення не потрібний, тобто:

 a = x & 00000001b 

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

 d = x >> 4 

1.3. Заміна бітового поля

  1. Очистити x від попереднього значення побітовим множенням на маску з нулями у відповідних бітах.
  2. Побитово скласти x з новим значенням (зрушеним на потрібну кількість бітів)

Наприклад, якщо нам потрібно замінити d, то

 xnew = (x & 00001111b) | (d << 4) 

2. Операції над однобітових полями

Поля a і b мають довжину 1 біт - це дозволяє працювати з ними дещо іншими засобами.

2.1. Перевірка окремого біта

Для перевірки треба побитово помножити x операцією "І" на маску, у якої одна одиниця - у відповідній позиції. Якщо вийшов 0, біт дорівнює 0.

 b = ((x & 00000010b)! = 0) 

Перевірка, чи рівний одиниці хоча б один біт з декількох:

 a_or_b = ((x & 00000011b)! = 0) 

Перевірка, чи рівні одиниці всі біти з декількох:

 a_and_b = ((x & 00000011b) == 00000011b) 

2.2. Установка бітів

Для цього треба скласти операцією "АБО" x з маскою, у якої одиниці у відповідних позиціях. Наприклад, щоб включити біт a:

 x1 = x | 00000001b 

Щоб включити і a, і b:

 x2 = x | 00000011b 

2.3. Зняття бітів

Щоб зняти один або кілька бітів, треба скласти x операцією "І" з маскою, у якій у відповідних позиціях нулі. Зокрема, щоб вимкнути біт b, потрібно дати команду:

 x3 = x & 11111101b 

2.4. Перемикання бітів

Для перемикання бітів (з 0 на 1, з 1 на 0) треба скласти x командою " Виключає АБО "з маскою, у якій у відповідних позиціях одиниці. Наприклад, біт b перемикається так:

 x4 = x ^ 00000010b 

3. Операції над знаковими полями в додатковому коді

Існують два способи зберігання негативних цілих чисел - знаковий біт і додатковий код. У переважній більшості сучасних машин застосовується другий. При записі негативних чисел додатковим кодом маємо:

 -1 = 11111111b -2 = 11111110b -3 = 11111101b -4 = 11111100b і т. д. 

Вважаємо, що поля c і d мають саме такий формат. Тоді поле c може зберігати числа від -2 = 10 2 до 1 = 01 2, а поле d - від -8 = 1000 2 до 7 = 0111 2.


3.1. Збірка і заміна чисел

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

 x = (d << 4) + ((c & 00000011b) << 2) + (b << 1) + a 

3.2. Витяг чисел

Для вилучення чисел потрібно зрушити поле на потрібну кількість бітів вправо, заодно розмноживши знаковий біт. Наприклад, для цього можна скористатися арифметичним зрушенням. Якщо x має довжину 8 бітів, то

 c = (x << 4) >> a 6 d = x >> a 4 

Увага! В мові програмування Java все навпаки: знаком >> позначається арифметичний зрушення, знаком >>> - простий.

Якщо арифметичного зсуву немає, то ...

 c1 = x >> 2 якщо (c1 & 00000010b ≠ 0) то c = c1 | 0x11111100b інакше c = c1 & 0x00000011b 

4. Оголошення бітових полів

4.1. У мові C / C + +

У декларації бітового поля використовується двокрапка, за якою слідує константне вираз визначає кількість бітів в поле [1];

 struct rgb {unsigned r: 3; unsigned g: 3; unsigned b: 3;}; 

Примітки

  1. Рей Лішнер [ [1] - oreilly.com/catalog/97805960029850 С + +. Довідник] = C + + In a Nutshell / гол. ред. Є. Строгонова. - СПб. : Питер, 2003. - С. 193. - 907 с. - 3500 екз. - ISBN 5-94723-928-0, ББК 32.973-018.1я22, 681.3.06 (03)