Логічний оператор ( ||
і &&
) проти побітових операторів ( |
і &
).
Найбільш важлива відмінність між логічним оператором і бітовим оператором полягає в тому, що логічний оператор приймає два булевих і виробляє булевий, а побітовий оператор приймає два цілі числа і виробляє ціле число (зверніть увагу: цілі числа означають будь-який інтегральний тип даних, а не просто int).
Щоб бути педантичним, побітовий оператор приймає біт-шаблон (наприклад, 01101011) і робить біт-розумним І / АБО на кожен біт. Так, наприклад, якщо у вас є два 8-бітні цілі числа:
a = 00110010 (in decimal: 32+16+2 = 50)
b = 01010011 (in decimal: 64+ 16+2+1 = 83)
----------------
a & b = 00010010 (in decimal: 16+2 = 18)
a | b = 01110011 (in decimal: 64+32+16+2+1 = 115)
тоді як логічний оператор працює лише у bool
:
a = true
b = false
--------------
a && b = false
a || b = true
По-друге, часто можна використовувати побітовий оператор на bool, оскільки true і false дорівнює 1 і 0 відповідно, і буває, що якщо ви перекладете true на 1, а false на 0, то виконайте побітову операцію, а потім перетворите ненульовий до істинного і від нуля до хибного; трапляється, що результат буде таким самим, якби ви щойно використовували логічний оператор (перевірте це на вправу).
Інша важлива відмінність також полягає в тому, що логічний оператор є короткозамкненим . Таким чином, у деяких колах [1] ви часто бачите людей, які роблять щось подібне:
if (person && person.punch()) {
person.doVictoryDance()
}
що означає: "якщо людина існує (тобто не є нульовою), спробуйте вдарити її / її, і якщо удар вдасться (тобто повертає справжнє), тоді робіть танець перемоги" .
Якщо ви замість цього використовували побітовий оператор, це:
if (person & person.punch()) {
person.doVictoryDance()
}
перекладається на: "якщо людина існує (тобто не є нульовою) і удар вдався (тобто повертає істину), тоді робіть танець перемоги" .
Зауважте, що в логічному операторі з коротким замиканням person.punch()
код може взагалі не працювати, якщо він person
є нульовим. Насправді в цьому конкретному випадку другий код створив би нульову посилання помилки, якщо він person
є нульовим, оскільки він намагається викликати person.punch()
незалежно від того, чи є людина нульовою чи ні. Така поведінка не оцінювання правильного операнда називається коротким замиканням .
[1] Деякі програмісти будуть шукати виклик функції, який має побічний ефект всередині if
виразу, а для інших це загальна і дуже корисна ідіома.
Оскільки бітовий оператор одночасно працює над 32-бітовою машиною (якщо ви працюєте на 32-розрядній машині), це може призвести до більш елегантного та швидшого коду, якщо вам потрібно порівняти величезну кількість умов, наприклад
int CAN_PUNCH = 1 << 0, CAN_KICK = 1 << 1, CAN_DRINK = 1 << 2, CAN_SIT = 1 << 3,
CAN_SHOOT_GUNS = 1 << 4, CAN_TALK = 1 << 5, CAN_SHOOT_CANNONS = 1 << 6;
Person person;
person.abilities = CAN_PUNCH | CAN_KICK | CAN_DRINK | CAN_SIT | CAN_SHOOT_GUNS;
Place bar;
bar.rules = CAN_DRINK | CAN_SIT | CAN_TALK;
Place military;
military.rules = CAN_SHOOT_CANNONS | CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT;
CurrentLocation cloc1, cloc2;
cloc1.usable_abilities = person_abilities & bar_rules;
cloc2.usable_abilities = person_abilities & military_rules;
// cloc1.usable_abilities will contain the bit pattern that matches `CAN_DRINK | CAN_SIT`
// while cloc2.usable_abilities will contain the bit pattern that matches `CAN_PUNCH | CAN_KICK | CAN_SHOOT_GUNS | CAN_SIT`
Зробити те саме з логічними операторами зажадає незручна кількість порівнянь:
Person person;
person.can_punch = person.can_kick = person.can_drink = person.can_sit = person.can_shoot_guns = true;
person.can_shoot_cannons = false;
Place bar;
bar.rules.can_drink = bar.rules.can_sit = bar.rules.can_talk = true;
bar.rules.can_punch = bar.rules.can_kick = bar.rules.can_shoot_guns = bar.rules.can_shoot_cannons = false;
Place military;
military.rules.can_punch = military.rules.can_kick = military.rules.can_shoot_guns = military.rules.can_shoot_cannons = military.rules.can_sit = true;
military.rules.can_drink = military.rules.can_talk = false;
CurrentLocation cloc1;
bool cloc1.usable_abilities.can_punch = bar.rules.can_punch && person.can_punch,
cloc1.usable_abilities.can_kick = bar.rules.can_kick && person.can_kick,
cloc1.usable_abilities.can_drink = bar.rules.can_drink && person.can_drink,
cloc1.usable_abilities.can_sit = bar.rules.can_sit && person.can_sit,
cloc1.usable_abilities.can_shoot_guns = bar.rules.can_shoot_guns && person.can_shoot_guns,
cloc1.usable_abilities.can_shoot_cannons = bar.rules.can_shoot_cannons && person.can_shoot_cannons
cloc1.usable_abilities.can_talk = bar.rules.can_talk && person.can_talk;
bool cloc2.usable_abilities.can_punch = military.rules.can_punch && person.can_punch,
cloc2.usable_abilities.can_kick = military.rules.can_kick && person.can_kick,
cloc2.usable_abilities.can_drink = military.rules.can_drink && person.can_drink,
cloc2.usable_abilities.can_sit = military.rules.can_sit && person.can_sit,
cloc2.usable_abilities.can_shoot_guns = military.rules.can_shoot_guns && person.can_shoot_guns,
cloc2.usable_abilities.can_talk = military.rules.can_talk && person.can_talk,
cloc2.usable_abilities.can_shoot_cannons = military.rules.can_shoot_cannons && person.can_shoot_cannons;
Класичний приклад, коли використовуються бітові шаблони та бітовий оператор, є дозволами файлової системи Unix / Linux.