Operador lógico ( ||
y &&
) vs. operador bit a bit ( |
y &
).
La diferencia más crucial entre un operador lógico y un operador bit a bit es que un operador lógico toma dos booleanos y produce un booleano, mientras que un operador bit a bit toma dos enteros y produce un entero (nota: enteros significa cualquier tipo de datos integral, no solo int).
Para ser pedante, un operador bit a bit toma un patrón de bits (por ejemplo, 01101011) y realiza un AND / OR en cada bit. Entonces, por ejemplo, si tiene dos enteros de 8 bits:
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)
mientras que un operador lógico solo funciona en bool
:
a = true
b = false
--------------
a && b = false
a || b = true
En segundo lugar, a menudo es posible usar un operador bit a bit en bool ya que verdadero y falso es equivalente a 1 y 0 respectivamente, y sucede que si traduce verdadero a 1 y falso a 0, entonces realiza una operación a nivel de bit, luego convierte un valor distinto de cero a verdadero y cero a falso; sucede que el resultado será el mismo si hubiera utilizado el operador lógico (verifique esto para hacer ejercicio).
Otra distinción importante es también que un operador lógico está en cortocircuito . Por lo tanto, en algunos círculos [1], a menudo se ve gente haciendo algo como esto:
if (person && person.punch()) {
person.doVictoryDance()
}
que se traduce como: "si la persona existe (es decir, no es nula), intente golpearla, y si el golpe tiene éxito (es decir, vuelve verdadero), entonces haga un baile de victoria" .
Si hubiera utilizado un operador bit a bit en su lugar, esto:
if (person & person.punch()) {
person.doVictoryDance()
}
se traducirá a: "si la persona existe (es decir, no es nula) y el golpe tiene éxito (es decir, vuelve verdadero), entonces haga un baile de victoria" .
Tenga en cuenta que en el operador lógico en cortocircuito, el person.punch()
código puede no ejecutarse si person
es nulo. De hecho, en este caso particular, el segundo código produciría un error de referencia nulo si person
es nulo, ya que intenta llamar person.punch()
sin importar si la persona es nula o no. Este comportamiento de no evaluar el operando correcto se llama cortocircuito .
[1] Algunos programadores criticarán por poner una llamada de función que tenga un efecto secundario dentro de una if
expresión, mientras que para otros es un idioma común y muy útil.
Dado que un operador bit a bit trabaja en 32 bits a la vez (si está en una máquina de 32 bits), puede generar un código más elegante y rápido si necesita comparar una gran cantidad de condiciones, por ejemplo
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`
Hacer lo mismo con operadores lógicos requeriría una cantidad incómoda de comparaciones:
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;
Un ejemplo clásico donde se usan patrones de bits y operadores bit a bit es en los permisos del sistema de archivos Unix / Linux.