位運算是嵌入式與系統程式設計的核心技能。本文系統整理位運算與邏輯運算的關鍵特性(短路求值、移位等價乘除、位元組合技巧),並展示三種無需第三變數交換兩數的經典演算法,最後解析緩衝區刷新與有號/無號比較陷阱。
| 運算子 | 短路規則 | 口訣 |
|---|---|---|
| 左運算元為假(0),右運算元不執行 | 一假則假 | |
| 左運算元為真(非0),右運算元不執行 | 一真則真 |
int a = 7, b = 9, c = 0;
printf("%d\n", a > b && c++); // 0,c 不遞增
printf("%d\n", c); // 0
printf("%d\n", a < b || c++); // 1,c 不遞增
printf("%d\n", c); // 0
<< n ≡ 乘以 2^n(溢位截斷)>> n ≡ 除以 2^n(有號算術右移補符號位,無號邏輯右移補 0)場景:將 32 位暫存器 reg 的第 15~12 位設為 0101(二進位)。
unsigned int reg = 0xFFFF7FFF;
// 1. 先清零目標位:建立遮罩 1111 << 12 = 0xF000,取反後 AND
reg = reg & ~(15 << 12); // 清除 bit 12-15
// 2. 再寫入目標值:0101 = 5,左移 12 位後 OR
reg = reg | (5 << 12); // 設定 bit 12-15 = 0101
// 合寫一行(注意運算子優先序)
reg = (reg & ~(15 << 12)) | (5 << 12);
通用模式:(reg & ~(mask << pos)) | (value << pos)
| 方法 | 程式碼 | 優缺點 |
|---|---|---|
| 加減法 | a = a + b - (b = a); | 可能溢位,序列點陷阱 |
| XOR 交換 | a ^= b; b ^= a; a ^= b; | 無溢位風險,但同位址會歸零 |
| 複合賦值 | a += b -= a = b; (未定義行為) | ❌ 避免使用 |
推薦:現代編譯器優化極佳,直接寫 std::swap(a, b) 或 int t=a; a=b; b=t; 最清晰安全。
int d = getchar(); // 輸入 'A' + Enter
int c = getchar(); // 直接讀到 '\n' (ASCII 10)
\r\n 兩字元;二進位模式:\n。\n,無轉換。getchar() 吃掉換行,或用 scanf(" %c", &ch)(前置空白跳過換行)。\n:換行 + 刷新標準輸出緩衝區(行緩衝模式)。\t、 等:不刷新,資料留在緩衝區,直到 \n、fflush(stdout)、程式結束或緩衝區滿。printf("Hello World!\n"); // 立即顯示
printf("Welcome\t"); // 不顯示
sleep(3);
printf("Test!!!\t"); // 3 秒後一次性顯示 "Welcome Test!!!"
unsigned int a = 10;
int b = -30;
if (a < b) // a 隱式轉為無號大數,條件為真!輸出 "a < b"
規則:混合比較時,有號隱式轉換為無號。-30 變為 4294967266,遠大於 10。
避坑:強制轉型 if ((int)a < b) 或統一使用有號型別。
if (sizeof(char) - sizeof(int) > 0) // sizeof 回傳 size_t (無號),結果為巨大正數
if (sizeof(char) > sizeof(int)) // 正確:直接比較兩個 size_t
p && p->foo())。\t 輸出延遲,需主動 fflush。sizeof 無號特性是 C 語言高頻 Bug 來源,務必建立型別敏感度。