Сервісний центр VPSGroup ремонт комп'ютерної техніки, заправка картриджів, ремонт оргтехніки, Київ, Виставковий центр, Васильківська, 55

Побітові оператори в PowerShell.

Давним давно, коли комп'ютери були дуже великими і дуже повільними, оперативної пам'яті в них було мало і її намагалися використовувати максимально ефективно. Наприклад у змінній типу bool є всього два можливих значення (true і false), які теоретично можуть бути представлені одним бітом, а за фактом займають цілий байт пам'яті.Це відбувається через те, що змінні використовують унікальні адреси пам'яті, які виділяються в байтах. В результаті змінна займає всього 1 біт, а решта 7 витрачаються даремно.

Уникнути марної трати пам'яті можна за допомогою побітових операторів. Побітові оператори, як випливає з назви, дозволяють оперувати безпосередньо битами.З їх допомогою можна вмістити 8 значень типу bool в змінної розміром 1 байт, що значно заощадить споживання пам'яті.

Сьогодні комп'ютерні потужності багаторазово зросли і вже немає необхідності економити кожен біт. Проте побітові оператори все ще використовуються, хоча і набагато рідше.У будь-якому випадку знати про них не завадить хоча б для загального розвитку.

PowerShell підтримує всі стандартні побітові оператори включаючи побітовое І (-band), побітовое АБО (-bor), побітовое виключає АБО (-bxor) і побітовое НЕ (-bnot). А починаючи з третьої версії в PowerShell з'явилися оператори побітового зсуву.Операцій зсуву дві - бітовий зсув вліво (-shl) і бітовий зсув вправо (-shr). Почнемо з побітових операторів порівняння.

Побітове І (bitwise AND, bAND)

Побітові оператори використовують двійковий формат значень. Наприклад число 1 буде виглядати як 00000001, а число 3 - як 00000011 (з урахуванням 1 байт - 8 біт).

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

Як приклад візьмемо числа 1 і 3 і переведемо їх в двійковий вигляд. Потім (для наочності) розмістимо числа одне над іншим і застосуємо операцію побітового І до кожного колонки з битами. В результаті операції отримаємо 1.

0000 0001 (1)
0000 0011 (3)
-------- bAND
0000 0001 (1)

В PowerShell для операції побітового І використовується оператор -band.Наприклад:

1 -band 3



Побітове АБО (bitwise OR, bOR)

При операції побітового АБО (що включає) результуючий біт дорівнює 1 в тому випадку, якщо хоча б один з вхідних бітів дорівнює 1. якщо ж обидва вхідних біта дорівнюють 0, то результат теж дорівнює 0.

Для прикладу виконаємо операцію побітового АБО над числами 1 і 3, в результаті отримаємо 3.

0000 0001 (1)
0000 0011 (3)
-------- bOR
0000 0011 (3)

В PowerShell для операції побітового АБО використовується оператор -bor. Наприклад:

1 -bor 3



Що виключає побітовое АБО (bitwise exclusive OR, bXOR)

Операція виключає побітового АБО повертає 1 в тому випадку, якщо тільки один з вхідних бітів дорівнює 1.Якщо обидва вхідних біта дорівнюють 1 або 0, то результат дорівнює 0. Так в результаті операції виключає побітового АБО над "багатостраждальними" числами 1 і 3 отримаємо 2.

0000 0001 (1)
0000 0011 (3)
-------- bXOR
0000 0010 (2)

В PowerShell операція виключає побітового АБО реалізована за допомогою оператора -bxor.Наприклад:

1 -bxor 3



Побітове НЕ (bitwise NOT, bNOT)

На перший погляд побітовое НЕ - найпростіший для розуміння оператор. Операція побітового НЕ просто змінює кожен біт числа на протилежний (0 на 1 або 1 на 0).

Для прикладу візьмемо число 00000011 (3) і застосуємо до нього оператор bnot.В результаті інверсії отримаємо число 11111100, яке при перекладі в десяткову систему дасть негативний число -4.

0000 0011 (3)
-------- bNOT
1111 1100 (-4)

Для побітового заперечення в PowerShell використовується оператор -bnot:

-bnot 3



До речі, при використанні оператора bnot можна помітити одну цікаву закономірність.При інвертуванні позитивного числа ми завжди отримуємо початкове число з протилежним знаком плюс одиниця, негативного - мінус одиниця.



У вас може виникнути цілком закономірне питання - чому оператор -bnot змінює знак числа. Справа в тому, що за замовчуванням в PowerShell використовується підписана уявлення чисел.Для представлення негативних чисел в двійковій системі використовується так званий додатковий код. Додатковий код двійкового числа виходить шляхом застосування до кожного біту числа (крім старшого, яке вважається знаковим) операції інверсії і додаванні до отриманого числа 1.

Так у випадку з -4 беремо десяткове число 4 і переводимо його в двійковий вигляд (прямий код), потім інвертуємо значення (отримуємо зворотний код), до отриманої інверсії додаємо 1 і в результаті отримуємо десяткове число -4 в додатковому коді:

0000 0100 (прямий код)
1111 1011 (зворотний код)
0000 0001
-------
1111 1100 (додатковий код)

Сподіваюся з цим все більш-менш зрозуміло, йдемо далі.

Побітовий зрушення вліво (shift bits left, shl)

Бітовий зрушення вліво зрушує біти вліво на вказану кількість, дописуючи справа нулі. Для прикладу візьмемо число 3, переведемо його в двійковий вигляд і зрушимо на один біт вліво. В результаті отримаємо 6.

0000 0011 (3)
-------- shl 1
0000 0110 (6)

Зрушення на 2 біта дасть число 12

0000 0011 (3)
-------- shl 2
0000 1100 (12)

на 3 біти - вже 24.

0000 0011 (3)
-------- shl 3
0001 1000 (24)

За аналогією з математичними операціями зрушення вліво можна уявити як множення на 2 певною мірою N. зрушення на 1 біт - множення на 21, на 2 біта - множення на 22, на 3 біти - множення на 23. І так далі.

в PowerShell зрушення вліво здійснюється за допомогою оператора -shl, наприклад:

3 -shl 1
3 -shl 2
3 -shl 3



Побітовий зрушення вправо (shift bits right, shr)

Бітовий зрушення вправо зрушує біти числа вправо, дописуючи зліва нулі.При цьому вийшли за межі числа біти відкидаються. Так якщо взяти число 12 і зрушити на 1 біт вправо, то вийде 6

00001100 (12)
-------- shr 1
00000110 (6)

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

00001100 (12)
-------- shr 2
00000011 (3)

а зрушення на 3 біта поверне 1.

00001100 (12)
-------- shr 3
00000001 (1)

Т.е зрушення вправо можна порівняти з розподілом на 2 певною мірою N з відкиданням залишку від ділення:

Зрушення на 1 біт 12/21 = 6
Зрушення на 2 біта 12/22 = 3
зрушення на 3 біта 12/23 = 1

В PowerShell правий зсув здійснюється за допомогою оператора -shr. Наприклад:

12 -shr 1
12 -shr 2
12 -shr 3



Приклад

в PowerShell побітові оператори використовуються досить рідко, принаймні у мене ніколи не було необхідності застосовувати їх в своїх скриптах.Але тим не менше мені вдалося знайти досить цікавий приклад їх використання. Приклад цей пов'язаний з мережами.

Наступний скрипт призначений для того, щоб порівнювати IP адреса і маску підмережі на предмет того, чи належить адреса даної підмережі.

[CmdletBinding ()]

Param (
[Parameter (Mandatory = $ true, Position = 1)]
[string] $ subnet,
[Parameter (Mandatory = $ true, Position = 2) ]
[string] $ ip
)

$ network, [int] $ subnetlen = $ subnet.Split ( '/');
$ a = [uint32 []] $ network.split ( '. `);
[uint32] $ unetwork = ($ a [0] -shl 24) + ($ a [1] -shl 16) + ($ a [2] -shl 8) + $ a [3];
$ mask = (-bnot [uint32] 0) -shl (32 - $ subnetlen );
$ b = [uint32 []] $ ip.split ( '. `);
[uint32] $ uip = ($ b [0] -shl 24) + ($ b [1 ] -shl 16) + ($ b [2] -shl 8) + $ b [3];
$ unetwork -eq ($ mask -band $ uip);

Працює так - вводимо мережу, адреса хоста і отримуємо True або False.



А тепер давайте більш детально розглянемо, як це працює.Коротко нагадаю, що IP-адреса являє собою 32-бітове число, що складається з двох частин - адреси мережі і адреси хоста. У свою чергу підмережа має мережеву адресу і довжину в бітах (маску підмережі), що становить мережеву частину адреси. Наприклад 192.168.0.0/16 означає мережу з адресою 192.168.0.0 і маскою 16. Маску 16 також можна записати як 255.255.0.0. Заглиблюватися далі не буду, про маски, адреси та інше дуже доступно написано тут.

Переходимо до скрипту. Як параметри скрипт приймає адресу мережі з маскою і адреса хоста:

Param (
[Parameter (Mandatory = $ true, Position = 1)]
[string] $ subnet,
[Parameter (Mandatory = $ true, Position = 2)]
[string] $ ip
)

Підмережа розбивається на власне адресу і маску за допомогою команди:

$ network, [int] $ subnetlen = $ subnet.Split ( '/');

Потім адреса мережі приводиться до типу Uint32 (32-бітове ціле число без знака). Спочатку адреса мережі розбивається на 4 частини по 8 біт (1 байт) кожна і поміщається в змінну у вигляді масиву. Потім кожен байт витягується з масиву і поміщається на своє місце в uint32 за допомогою побітового зсуву вліво.Щоб помістити $ a [3] в молодший байт, просто додаємо його (нульовий зсув), $ a [2] зрушуємо на 8 біт (1 байт), $ a [1] - на 16 біт (2 байти) і $ a [ 0] на 24 біта (3 байта):

$ a = [uint32 []] $ network.split ( '. `);
[uint32] $ unetwork = ($ a [0 ] -shl 24) + ($ a [1] -shl 16) + ($ a [2] -shl 8) + $ a [3];

Для розрахунку маски мережі береться число, зворотне 0 , наведене до типу uint32:

(- bnot [uint32] 0)

Кількість нулів в масці підмережі одно (32 - $ subnetlen).Виробляємо зрушення вліво на це число і отримуємо маску підмережі:

$ mask = (-bnot [uint32] 0) -shl (32 - $ subnetlen)

З адресою хоста виробляємо такі ж маніпуляції, як і з адресою мережі:

$ b = [uint32 []] $ ip.split ( '. `)
[uint32] $ uip = ($ b [0] -shl 24) + ($ b [1] -shl 16) + ($ b [2] -shl 8) + $ b [3]

в результаті отримуємо адресу підмережі та адресу хоста у вигляді Uint32.Обчислюємо мережеву частину адреси хоста за допомогою побітового І (band), результат порівнюємо з адресою підмережі:

$ unetwork -eq ($ mask -band $ uip)

Якщо адреси однакові, значить IP адреса хоста потрапляє в зазначену підмережа, різні - не потрапляє.

.