首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 運算符與表達式完全手冊:優先級、結合性、隱式轉換與實戰陷阱

     編輯:關於C++

前言

運算符是構建表達式的基石,理解優先級、結合性、操作數類型轉換規則,是編寫無 Bug 表達式的前提。本文系統梳理 C++ 所有運算符分類、優先級表、關鍵運算符語義、隱式類型轉換規則、常見表達式陷阱,提供查閱表與實戰代碼驗證。

一、運算符分類總覽

分類代表運算符目數
後綴() [] -> . ++ --1
一元/前綴++ -- + - ! ~ * & sizeof new delete1
類型轉換(type)1
成員指針.* ->*2
算術* / % + -2
移位<< >>2
關系< <= > >=2
相等性== !=2
位與&2
位異或^2
位或|2
邏輯與&&2
邏輯或||2
條件? :3
賦值= += -= *= /= %= &= ^= |= <<= >>=2
逗號,2

二、優先級與結合性完整表 (高→低)

1.  ::              域解析               左→右
2.  () [] -> . ++-- 後綴/成員訪問        左→右
3.  ++ -- + - ! ~ * & sizeof new delete  一元/前綴          右→左
4.  .* ->*          成員指針             左→右
5.  * / %           乘除模               左→右
6.  + -             加減                 左→右
7.  << >>           移位                 左→右
8.  < <= > >=       關系                 左→右
9.  == !=           相等性               左→右
10. &               位與                 左→右
11. ^               位異或               左→右
12. |               位或                 左→右
13. &&              邏輯與               左→右  (短路)
14. ||              邏輯或               左→右  (短路)
15. ? :             條件運算符           右→左
16. = += -= ...     賦值運算符           右→左
17. ,               逗號運算符           左→右

口訣:單目 > 算術 > 移位 > 關系 > 相等 > 位運算 > 邏輯與 > 邏輯或 > 條件 > 賦值 > 逗號。

三、關鍵運算符深度解析

1. 關系運算符 (< <= > >=)

  • 優先級高於 == !=。
  • 結果為 bool (true/false)。
  • 鏈式比較 a < b < c 解析為 (a < b) < c,**非數學意義**,C++20 引入 a < b < c 合法但極少用。

2. 相等性運算符 (== !=)

  • 優先級低於關系運算符。
  • 指針比較:比較地址值;nullptr 只能與指針比較。
  • 浮點數比較**慎用 ==**,建議 fabs(a-b) < eps。

3. 條件運算符 (? :) —— 唯一三目運算符


條件 ? 表達式1 : 表達式2
// 相當於
if (條件) 表達式1; else 表達式2;
  • 優先級**低於**邏輯運算符,**高於**賦值運算符。
  • 嵌套結合方向**右→左**:a ? b : c ? d : e 等價 a ? b : (c ? d : e)。
  • 表達式1/2 必須可隱式轉換為**同一類型**(或其中一個為 void)。

4. 邏輯運算符 (! && ||) —— 短路求值

運算符優先級結合性短路規則
!2 (最高)右→左無
&&13左→右左操作數為 false → 不計算右側
||14左→右左操作數為 true → 不計算右側

實戰利用短路:if (ptr && ptr->valid()) 避免空指針解引用;if (file.open() || createNewFile())。

5. 位運算符 (& | ^ ~ << >>)

  • 僅適用於整數類型。
  • ~ 按位取反,& 清零/掩碼,| 置位,^ 翻轉/交換。
  • 移位:左移 x << n 等價 x * 2^n,右移有符號數為算術移位(符號位擴展),無符號為邏輯移位(補 0)。

6. 賦值運算符 (= += ...)

  • 右結合:a = b = c = 1 等價 a = (b = (c = 1))。
  • 復合賦值 a += b 等價 a = a + b 但 a 只求值一次(對複雜表達式如 arr[i++] += 1 有差異)。

四、隱式類型轉換規則 (整型提升 + 常用算術轉換)

1. 整型提升

bool, char, signed char, unsigned char, short, unsigned short, enum → 提升為 int (若 int 不能表示所有值則為 unsigned int)。

2. 常用算術轉換 (雙目運算符雙操作數)

  1. 若有 long double → 另一轉 long double。
  2. 否則有 double → 另一轉 double。
  3. 否則有 float → 另一轉 float。
  4. 否則進行**整型提升**,然後:
    有 unsigned long long → 轉 unsigned long long
    有 long long → 轉 long long
    有 unsigned long → 轉 unsigned long
    有 long → 轉 long
    有 unsigned int → 轉 unsigned int
    否則雙方均為 int。

簡化版:浮點型按精度向高轉;整型先提升,再按「無符號優先、長度優先」轉換。

五、經典表達式陷阱驗證代碼


#include 
using namespace std;

int main() {
    // 1. 優先級陷阱
    int a = 3, b = 2, c = 1;
    cout << "a > b == c: " << (a > b == c) << endl; // (a>b) 是 1(true), 1 == c(1) → true(1)
    
    // 2. 短路求值
    int x = 0, y = 0;
    if (x++ && ++y) {} // x++ 為 0(false),短路,y 不自增
    cout << "x=" << x << " y=" << y << endl; // x=1, y=0
    
    // 3. 條件運算符嵌套
    int m = 10, n = 20, p = 30;
    int r = m > n ? m : n > p ? n : p; // m>n 假 → n>p 假 → p(30)
    cout << "r=" << r << endl;
    
    // 4. 後置++ 返回右值
    int i = 1;
    // i++++ 錯誤:後置++返回右值,不能再++
    // 前置++ 返回左值
    ++++i; // 合法:(++(++i)),i 變 3
    cout << "i=" << i << endl;
    
    // 5. 同一表達式多次後置++
    int x1 = 1;
    int y1 = (x1++) + (x1++); // 兩次用舊值 1+1=2,序列點後 x1=3
    cout << "y1=" << y1 << " x1=" << x1 << endl; // y1=2, x1=3
    
    // 6. sizeof vs strlen
    char str[] = "hello";
    cout << "sizeof=" << sizeof(str) << " strlen=" << strlen(str) << endl; // 6 vs 5
    
    // 7. 整型提升
    char c = 200; // 有符號 char 可能溢出,視實現定義
    cout << "c+1=" << (c+1) << endl; // c 提升為 int 運算
    
    return 0;
}

六、最佳實踐建議

  1. 括號明確意圖:複雜表達式**寧可多加括號**,不要依賴優先級記憶。
  2. 避免副作用疊加:單表達式中同一變量多次修改(i = i++ + ++i)為未定義行為 (C++17 前) 或未指定行為。
  3. 浮點比較用 epsilon:fabs(a-b) < 1e-9。
  4. 利用短路保護:指針判空在前,開銷大操作在後。
  5. 枚舉類用 enum class:強類型,避免隱式轉換為整數參與運算。
  6. 位運算用無符號類型:避免右移符號位擴展導致邏輯錯誤。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved