iT邦幫忙

1

【C++學習筆記】04《邏輯運算與運算子》

  • 分享至 

  • xImage
  •  

【C++學習筆記】03《你的變數不是你的變數》
【C++學習筆記】05《行為定義》


在 C++ 中,邏輯運算子(Logical Operators) 主要用來處理條件判斷,邏輯運算在執行時,會伴隨隱性轉型、短路求值,以及可能發生的副作用,若不了解其運作方式,容易在條件判斷中產生非預期結果。看似簡單,但其實藏了不少容易忽略或常忘的細節。

一、bool與隱性轉型(Implicit Conversion)
在 C++ 中,bool 可以自動轉換成整數型別:

true  -> 1
false -> 0

因此以下程式碼是合法的:

int a = true + true;   // a = 2
int b = false + 5;    // b = 5

這種轉換稱為隱性轉型,由編譯器根據「運算子與型別」自動決定。
📌 注意:
◆bool → int是允許的
◆反過來int → bool則是0為false,非0為true
◆此轉換僅適用於 C++ 內建算術型別之間,屬於標準隱性轉型(standard conversion)。

二、邏輯運算子(Logical Operators)
C++ 提供三種基本邏輯運算子:

&&  // AND
||  // OR
!   // NOT

使用範例:

int a = 0;
int b = 1;
    
if(a == 0 && b == 1)
{
    cout << "true" << endl;//print "true"
}
if(a == 0 || b == 0)
{
    cout << "true";//print "true"
}

! 只需要一個運算元,用來反轉布林結果:

!(3 > 2)   // false
等同於
not (3 > 2)//not為替代關鍵字
int a = 0;
int b = 1;
    
if(!(a > b))
{
    cout << "A";//print A
}

C++ 也提供對應的保留字:and/or/not關鍵字

if (a > 0 and b > 0) {}
符號   關鍵字
&&   | and
||   | or
!    | not

📌實務上大多仍使用符號版本,閱讀他人程式碼時需能辨識。

邏輯運算與副作用(Side Effect)
副作用在程式開發中可謂極其重要,在運算或函式呼叫過程中,除了回傳值之外,還改變了程式狀態,例如:
-修改變數的值
-改變物件狀態
-I/O操作
-呼叫具有狀態影響的函式

常見具有副作用的操作

i++;        // 修改 i
++i;
i = 5;
func();     // 若func內部修改狀態

短路求值與副作用
在 C++ 中:
◆&&:若左邊為false,右邊不會執行
◆||:若左邊為true,右邊不會執行
這稱為短路求值(Short-circuit Evaluation),此特性會直接影響具有副作用的運算是否會被執行。

int i = 0;
if (false && ++i)
{
    // 不會進入
}
cout << i;  // i 仍為 0

📌因此,條件判斷中應避免依賴副作用來完成必要邏輯
三、運算只會一次做一件事
本節後續內容雖不全屬於邏輯運算子,但皆與「運算式求值順序、隱性轉型與條件判斷安全性」密切相關,因此一併整理。

C++ 不會同時執行多個運算,而是依序進行。但是,C++不會保證所有運算的求值順序,若語言規範未明確定義順序,結果可能因編譯器而異。
實際執行順序由以下因素決定:
-運算子優先順序
-運算子結合性(Associativity)
-隱性轉型規則

賦值運算子的順序
在C++中,賦值運算子(=)是右結合(right-associative),
這代表在同一個運算式中,會先解析右邊的賦值結果,再套用到左邊。

a = b = c = 9;

實際的解析方式等同於:

a = (b = (c = 9));

const:讓物件成為唯讀
const用來表示「初始化後不可再被修改」。

const int x = 10;
x = 20; // 編譯錯誤

使用 const 的好處:
◆避免誤修改
◆提高程式可讀性
◆讓編譯器進行更多檢查與最佳化

複合賦值運算子
複合賦值只是語法的簡化,但仍是正式運算。

a += 5;  // a = a + 5
a -= 3;
a *= 2;
a /= 4;

遞增與遞減運算子
a++與++a 的差異

int a = 5;

int x = a++;  // x = 5, a = 6
int y = ++a;  // a = 7, y = 7

📌差異在於:
a++:先使用,再遞增
++a:先遞增,再使用

未定義行為(Undefined Behavior)
以下程式碼是錯誤示範:

a = a++;

在同一運算式中,對同一變數的修改與讀取之間沒有明確的求值順序(sequencing),因此屬於未定義行為。

未定義行為(Undefined Behavior, UB)將在下一章節單獨整理筆記。


如果你也是非本科背景,或正準備開始學習程式,希望這篇筆記能對你有所幫助。
這裡會持續記錄我在轉職過程中對程式、軟體工程與實務學習的理解,歡迎一起交流,也歡迎指教。
如果這篇內容對你有幫助,歡迎收藏或分享給正在學習程式的朋友。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
meebox
iT邦新手 3 級 ‧ 2026-02-04 10:25:17

這裡可能會有點誤導:

a = b = c = 9;

等同於

c = 9;
b = c;
a = b;

不過實際上應該是等同於:

a = (b = (c = 9));

所以會先計算 c = 9,由於 = 運算子的運算結果是 = 運算子右側運算式 9 的運算結果,副作用則是把 c 設為 9,所以上述運算式會變成:

a = (b = 9); // c 變成 9

同理,計算 b = 9 後,這個運算式的運算結果是 = 運算子右側的運算式 '9' 的值,副作用是把 b 設為 9,所以上述運算式會等同於:

a = 9 // b 變成 9

才會得到 a,b,c 都會是 9 的結果。

建議講述運算子的時候,運算子的運算結果與副作用是很重要的一環。像是 a++++a 都具備同樣的副作用,會讓 a 遞增,但是差別是後置的 ++ 運算結果是 a 的原始值,但前置的 ++ 運算結果是 a+1,所以

int a = 5;

int x = a++;  // x = 5, a = 6
int y = ++a;  // a = 7, y = 7

等同於

int x = 5; // 因為 a++ 的計算結果是 a,
           // 這個敘述結束後,a 一定會變成 6

再變成:

int y = (6+1); // 因為 ++a 的運算結果是 a+1
               // 這個敘述結束後,a 一定會變成 7

只是規格書上並沒有規範 a 本身什麼時候遞增,只確保它所在的那一個 statement 結束時,一定會遞增,這才是為什麼會有未定義行為的原因,有的編譯器的確是會在 ++ 運算當下就改變 a 的值,但有的編譯器就不是,這都符合規格書。如果以『先遞增再使用』的方式來解說,就會覺得不是就已經遞增了,為什麼同一個運算式中第二次用到時會有未定義行為的疑問。

Kevin Lee iT邦新手 5 級 ‧ 2026-02-09 09:48:38 檢舉

感謝你補充!我原文把 a = b = c = 9; 用三行拆寫成 c=9; b=c; a=b; 確實容易讓人誤以為是單純的逐行順序。
另外,副作用確實也是初學時最容易混淆的地方,我會補強這部分說明,避免造成誤解,謝謝指正!

我要留言

立即登入留言