Логический оператор ( ||
и &&
) против побитового оператора ( |
и &
).
Наиболее существенное различие между логическим оператором и побитовым оператором заключается в том, что логический оператор принимает два логических значения и выдает логическое значение, в то время как побитовый оператор принимает два целых числа и выдает целое число (примечание: целые числа означают любой целочисленный тип данных, а не только 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.