| 運算符 | 名稱 | 行為 | 數學等價 |
|---|---|---|---|
<< | 左移 | 低位補 0,高位丟棄 | x * 2^k (無符號/無溢出時) |
>> | 右移 | 見下文 | x / 2^k (向下取整/向零取整視類型) |
數值: 1001 0101 (有符號 -107 / 無符號 149) 邏輯右移 4 (無符號/正數): 0000 1001 = 9 (補 0) 算術右移 4 (有符號負數): 1111 1001 = -7 (複製符號位 1)
>> 算術右移,>>> 邏輯右移,**語言級保證**。C 標準 (C99 6.5.7/3):**移位量 ≥ 左操作數位寬 → 未定義行為 (UB)**。
int x = 1; x << 32; // UB! 32 位 int 移位量 32 ≥ 32 x >> 36; // UB!
SHL/SHR 只取移位量低 5 位 (mod 32),導致 1 << 32 == 1,但**不可依賴**。shift & 0x1F (int) / shift & 0x3F (long),行為確定。assert(shift < width); 或 shift %= width; (但注意負數模)。C 優先級:**加減 > 移位**。
1 << 2 + 3 << 4 // 實際解析: 1 << (2+3) << 4 = 1 << 5 << 4 = 32 << 4 = 512 // 直覺期望: (1<<2) + (3<<4) = 4 + 48 = 52
鐵律:移位表達式混合其他運算符時,括號括起來!
-1 << 1 未定義。// 安全左移 (有符號)
int safe_shl(int x, int k) {
if (k < 0 || k >= (int)sizeof(int)*8) return 0; // 或 assert
if (x < 0) return 0; // 禁止負數左移
return x << k;
}
// 安全算術右移 (保證算術語義)
int safe_asr(int x, int k) {
if (k < 0 || k >= (int)sizeof(int)*8) return x >> 31; // 全符號位
return x >> k; // 依賴編譯器實現算術右移 (主流皆如此)
}
// 強制邏輯右移 (有符號視為無符號)
int forced_lsr(int x, int k) {
if (k < 0 || k >= (int)sizeof(int)*8) return 0;
return (unsigned)x >> k; // 轉無符號保證邏輯右移
}
x * 2 → x << 1 (無符號/無溢出有符號)x / 2 → x >> 1 **僅限無符號或非負有符號**。負數除法向零取整,算術右移向負無窮取整,不等價。編譯器會插入修正代碼:(x + (x>>31)) >> 1。(x >= 0) ? (x>>k) : ~(~x>>k) 模擬。0 <= k < WIDTH。uint32_t 等明確位寬,避免 int 16/32/64 位差異。C 語言移位運算看似簡單,實則暗藏 UB 陷阱 (移位量溢出、負數左移)、實現定義行為 (有符號右移)、優先級反直覺。專業開發者應:優先用無符號類型、括號明確優先級、斷言移位量合法、文檔假設右移語義、依賴編譯器優化而非手寫移位。跨平台代碼庫建議封裝安全移位函數,消除 UB 隱患。