Operatore logico ( ||
e &&
) vs. operatore bit per bit ( |
e &
).
La differenza più cruciale tra un operatore logico e un operatore bit a bit è che un operatore logico prende due valori booleani e produce un valore booleano mentre un operatore bit a bit prende due numeri interi e produce un numero intero (nota: numeri interi indica qualsiasi tipo di dati integrale, non solo int).
Per essere pedante, un operatore bit a bit prende un modello di bit (ad esempio 01101011) e fa un AND / OR bit per bit su ogni bit. Ad esempio, se hai due numeri interi a 8 bit:
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)
mentre un operatore logico lavora solo in bool
:
a = true
b = false
--------------
a && b = false
a || b = true
In secondo luogo, è spesso possibile utilizzare un operatore bit a bit su bool poiché true e false sono rispettivamente equivalenti a 1 e 0, e succede che se si traducono true in 1 e false in 0, quindi si eseguono operazioni bit a bit, quindi si converta un valore diverso da zero a vero e zero a falso; succede che il risultato sarà lo stesso se avessi appena usato un operatore logico (controlla questo per l'esercizio).
Un'altra importante distinzione è anche che un operatore logico è in corto circuito . Pertanto, in alcuni ambienti [1], spesso vedi persone che fanno qualcosa del genere:
if (person && person.punch()) {
person.doVictoryDance()
}
che si traduce in: "se la persona esiste (cioè non è nulla), prova a dargli un pugno, e se il pugno ha successo (cioè restituisce vero), allora fai una danza della vittoria" .
Se avessi usato invece un operatore bit per bit, questo:
if (person & person.punch()) {
person.doVictoryDance()
}
si tradurrà in: "se la persona esiste (cioè non è nulla) e il pugno ha successo (cioè restituisce vero), allora fai una danza della vittoria" .
Si noti che nell'operatore logico in cortocircuito, il person.punch()
codice potrebbe non essere eseguito affatto se person
è nullo. In effetti, in questo caso particolare, il secondo codice produrrebbe un errore di riferimento null se person
è null, poiché tenta di chiamare person.punch()
indipendentemente dal fatto che la persona sia null o meno. Questo comportamento di non valutazione dell'operando corretto si chiama corto circuito .
[1] Alcuni programmatori si affrettano a mettere una chiamata di funzione che ha un effetto collaterale all'interno di if
un'espressione, mentre per altri è un linguaggio comune e molto utile.
Poiché un operatore bit a bit lavora su 32 bit alla volta (se si utilizza una macchina a 32 bit), può portare a un codice più elegante e più veloce se è necessario confrontare un numero enorme di condizioni, ad es.
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`
Fare lo stesso con gli operatori logici richiederebbe una quantità scomoda di confronti:
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 esempio classico in cui vengono utilizzati schemi di bit e operatore bit per bit è nelle autorizzazioni del file system Unix / Linux.