# 簡易介紹C/C++中&, &&, |, ||的差別 * 在初學時,我們很常使用上述的符號來做IF的邏輯運算,例如以下範例: ```cpp int main() { bool IsKoreaFishLazy = true; bool IsKaohsiungRich = false; if(IsKaohsiungRich && IsKoreaFishLazy) cout<<"a"; if(IsKaohsiungRich & IsKoreaFishLazy) cout<<"b"; if(IsKaohsiungRich || IsKoreaFishLazy) cout<<"c"; if(IsKaohsiungRich | IsKoreaFishLazy) cout<<"d"; } ``` ``` Output: cd ``` * 從簡單的true/false判斷來看,乍看下好像是等價,但是實際上兩者是有相當大的差別的。 ## (&,|) 算術運算子 * &與|是"算術運算子",意思就是這兩個符號是用在對於bit的運算,&對應至"AND",而|則是對應至"or",例如說以下面的bit運算為例: * (*註: bitset函式的作用是把數值以2進位顯示) ```cpp int main() { int a = 4; int b = -5; int c = a & b; int d = a | b; cout<<"a= "<<std::bitset<8>(a)<<endl; cout<<"b= "<<std::bitset<8>(b)<<endl; cout<<"c= "<<std::bitset<8>(c)<<endl; cout<<"d= "<<std::bitset<8>(d)<<endl; } ``` * Output: ``` a= 00000100 b= 11111011 c= 00000000 d= 11111111 ``` ## (&&,||) 邏輯運算子 * 而&&與||則是邏輯運算子,就是用來判斷true與false的狀態,如同最上面的if/else的例子,想當然而就不能拿來當作算術運算子來使用...嗎? ```cpp int main() { int a = 4; int b = -5; int c = a && b; int d = a || b; cout<<"a= "<<std::bitset<8>(a)<<endl; cout<<"b= "<<std::bitset<8>(b)<<endl; cout<<"c= "<<c<<endl; cout<<"d= "<<d<<endl; cout<<"c's hex= "<<std::bitset<8>(c)<<endl; cout<<"d's hex= "<<std::bitset<8>(d)<<endl; } ``` * Output: ``` a= 00000100 b= 11111011 c= 1 d= 1 c's hex= 00000001 d's hex= 00000001 ``` * 其實編譯還是會過的哦,但是結果很明顯跟算術運算子的結果不太一樣,從這個例子可以看出與算術運算子的差別以及一些規律。 * **只要是數值不為0,系統在邏輯運算上就會把它視為"true",反之則是"false"。** * **而"true"在二進位之值為"1",反之"false"為"0"**,以下有測試結果: ```cpp int main() { bool IsKoreaFishLazy = true; bool IsKaohsiungRich = false; cout<<std::bitset<8>(IsKoreaFishLazy)<<endl; cout<<std::bitset<8>(IsKaohsiungRich )<<endl; } ``` ``` 00000001 00000000 ``` ## 雖然知道底層的原理,但我們在條件判斷if/else上,好像還是可以混用啊? * 照上面的邏輯,我們再回到if/else判斷式範例: ```cpp int main() { bool IsKoreaFishLazy = true; bool IsKaohsiungRich = false; if(IsKaohsiungRich && IsKoreaFishLazy) cout<<"a"; if(IsKaohsiungRich & IsKoreaFishLazy) cout<<"b"; if(IsKaohsiungRich || IsKoreaFishLazy) cout<<"c"; if(IsKaohsiungRich | IsKoreaFishLazy) cout<<"d"; } ``` * 套用剛剛的結論,一個是把數值做bit做and/or運算,一個是轉成true/false判斷,在變數是單純的bool下這兩者結果是完全沒差的。 * 但此篇最重要的結論來了: **在AND的情況下,算術運算子&&因為bit運算的關係,一定會存取兩個變數並運算出結果,而邏輯運算值&只要第一個變數是false,就會直接跳出if判斷式** * 也就是說,if(IsKaohsiungRich && IsKoreaFishLazy)會讀取兩個變數的值(0與1)並且做AND運算,而if(IsKaohsiungRich & IsKoreaFishLazy)只要看到IsKaohsiungRich為false/0就會跳出了。 ## 不是阿,除了效率問題外,我還是可以混著用啊? * 當然不行,在某些狀況下是差很多的,以[此題leetcode為例](https://leetcode.com/explore/interview/card/top-interview-questions-easy/93/linked-list/560/),為了判斷linklist中,目前指標指向的node以及此node串接的下個node是否為NULL,我需要以下的判斷式: ```cpp if(head != nullptr && head -> next != nullptr) ``` * 在head為nullptr的情況下,假如說你使用&,讓兩邊的bool做and運算,第二個bool(head -> next != nullptr)會因為head為nullptr的情況下,我又想去access head,導致編譯器彈出錯誤: ``` Runtime Error Message: Line 12: Char 38: runtime error: member access within null pointer of type 'struct ListNode' (solution.cpp) Last executed input: [] ``` * 使用&&的話,只要看到我指向的head為nullptr就直接跳出了if,自然就不會有access nullptr的問題囉。 * 所以除了特殊狀況下,還是乖乖使用邏輯運算子吧! ## 延伸資料 * [codepad 好用的線上編譯器](http://codepad.org/) * [C++ bool 所占的記憶體空間與資料對齊 (data alignment)](https://www.cclo.idv.tw/blogs/closer/?p=184)