int main() {
int a = 0, b = 0, c = 0;
c = (a -= a - 5), (a = b, b + 3);
printf("%d,%d,%d\n", a, b, c); // 輸出 0,0,5
return 0;
}
整個表達式是一個**逗號運算子**串聯的兩個子表達式:
c = (a -= a - 5), (a = b, b + 3);
│ │ │ │
│ │ │ └─ 子表達式 2:(a = b, b + 3)
│ │ └─ 子表達式 1:(a -= a - 5)
│ └─ 賦值給 c
└─ 整個大表達式的值 (被丟棄)
(a -= a - 5)a - 5 → 0 - 5 = -5。a -= -5 等價 a = a - (-5) → a = 0 + 5 = 5。a,即 5。c = (子表達式1)c 被賦值為 5。(a = b, b + 3)這又是一個逗號運算子,左到右求值:
a = b → b 當前為 0,所以 a 變為 0。該子表達式值為 0。b + 3 → 0 + 3 = 3。該子表達式值為 3,**但未被賦值給任何變數**,純副作用運算 (此處無副作用)。3 (被外層丟棄)。a = b 覆蓋)輸出 0,0,5 完全吻合。
| 概念 | 規則 | 本題體現 |
|---|---|---|
逗號運算子 , | 左到右求值,**整體值為最右側子表達式的值**;常用於 for 迴圈多變量初始化/遞增、宏定義多語句。 | 外層、內層雙重逗號 |
複合賦值 -= | a -= b ≡ a = a - (b),右側完整運算後再賦值。 | a -= a - 5 非 a = a - a - 5 |
| 賦值運算子值 | 賦值表達式的值為**賦值後左操作數的值**。 | c = (a=5) 使 c=5 |
| 副作用與序列點 | C 標準規定:逗號運算子是序列點,左側副作用完成才執行右側。 | 保證 a=5 先於 a=b 執行 |
// ❌ 可讀性極差,維護噩夢
c = (a -= a - 5), (a = b, b + 3);
// ✅ 拆分為清晰語句
a = a - (a - 5); // a = 5
c = a; // c = 5
a = b; // a = 0
// b + 3 無副作用,刪除或單獨行
int temp = b + 3; // 若真需要這個值
面試官視角
這題考察:
1. 運算子優先級與結合性 (逗號最低,賦值右結合)。
2. 逗號運算子語義 (序列點、值取最右)。
3. 複合賦值展開規則。
4. **工程素養**:能否一眼看出這代碼不可維護,並重寫為清晰版本。