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 ifun'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.