Operator logiczny ( ||
and &&
) a operator bitowy ( |
and &
).
Najważniejsza różnica między operatorem logicznym a operatorem bitowym polega na tym, że operator logiczny przyjmuje dwie wartości logiczne i tworzy wartość logiczną, podczas gdy operator bitowy przyjmuje dwie liczby całkowite i tworzy liczbę całkowitą (uwaga: liczby całkowite oznaczają dowolny typ danych całkowitych, a nie tylko int).
Aby być pedantycznym, operator bitowy przyjmuje wzorzec bitowy (np. 01101011) i wykonuje bitowe AND / OR na każdym bicie. Na przykład, jeśli masz dwie 8-bitowe liczby całkowite:
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)
podczas gdy operator logiczny działa tylko w bool
:
a = true
b = false
--------------
a && b = false
a || b = true
Po drugie, często jest możliwe użycie operatora bitowego na bool, ponieważ prawda i fałsz są równoważne odpowiednio 1 i 0, i zdarza się, że jeśli przetłumaczysz true na 1 i false na 0, wykonaj operację bitową, a następnie przekonwertuj wartość niezerową na prawdę i zero na fałsz; zdarza się, że wynik będzie taki sam, gdybyś użył właśnie operatora logicznego (sprawdź to w ćwiczeniu).
Inną ważną różnicą jest również to, że operator logiczny jest zwarty . Dlatego w niektórych kręgach [1] często można zobaczyć, jak ludzie robią coś takiego:
if (person && person.punch()) {
person.doVictoryDance()
}
co oznacza: „jeśli osoba istnieje (tj. nie jest zerowa), spróbuj uderzyć ją / ją, a jeśli cios się powiedzie (tj. zwróci prawdę), wykonaj taniec zwycięstwa” .
Gdybyś zamiast tego użył operatora bitowego, to:
if (person & person.punch()) {
person.doVictoryDance()
}
przetłumaczy się na: "jeśli osoba istnieje (tj. nie jest zerowa) i cios się powiedzie (tj. zwróci prawdę), wtedy wykonaj taniec zwycięstwa" .
Zwróć uwagę, że w operatorze logicznym zwartym person.punch()
kod może w ogóle nie zostać uruchomiony, jeśli person
ma wartość null. W rzeczywistości w tym konkretnym przypadku drugi kod spowodowałby błąd odwołania zerowego, gdyby person
był zerowy, ponieważ próbuje wywołać person.punch()
bez względu na to, czy osoba jest pusta, czy nie. To zachowanie polegające na nieocenianiu prawidłowego operandu nazywane jest zwarciem .
[1] Niektórzy programiści wzbraniają się umieszczać wywołanie funkcji, które ma efekt uboczny wewnątrz if
wyrażenia, podczas gdy dla innych jest to powszechny i bardzo przydatny idiom.
Ponieważ operator bitowy działa jednocześnie na 32-bitowych bitach (jeśli korzystasz z maszyny 32-bitowej), może to prowadzić do bardziej eleganckiego i szybszego kodu, jeśli chcesz porównać ogromną liczbę warunków, np.
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`
Zrobienie tego samego z operatorami logicznymi wymagałoby niezręcznej ilości porównań:
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;
Klasycznym przykładem użycia wzorców bitowych i operatorów bitowych są uprawnienia systemu plików Unix / Linux.