<< 和 >> 是底层位操作,实际移位数由右操作数低5位(int)或低6位(long)决定,负移位数被禁止,>> 对负数为算术右移,小类型移位前自动提升为int易致符号扩展。
直接说结论:
和
不是简单的“乘2”或“除2”快捷写法,它们是底层位操作,行为由操作数类型和移位数的**低5位或低6位**决定,超出范围的移位数会被自动截断——这是绝大多数人踩坑的根源。
为什么
和
结果一样?
因为
是
(32位),C# 规定:实际移位数只取右操作数的**低5位**。33 的二进制是
,低5位是
(即 1),所以
等价于
。
对
或
:移位数 =
(即 % 32,但不是取模,是位与)
对
或
:移位数 =
(即 % 64)
右操作数为负数?编译不通过——C# 明确禁止负移位数
移位后高位溢出的部分直接丢弃,不会抛异常,也不会溢出检查(
也无效)
对负数是算术右移,不是逻辑右移
在 C# 中始终是**带符号右移**(arithmetic shift)。对负数,高位补的是符号位(1),不是 0。这意味着它不等价于数学上的整除,尤其在负数场景下结果容易误判。
C知道
CSDN推出的一款AI技术问答工具
下载
→ 结果是
(二进制
),符合预期
→ 仍是
(全 1 的补码不断补 1)
需要无符号右移?用
或
强制转成无符号类型再移
别试图用
做“清空高位”或“提取字节”,它依赖符号,行为不稳定
byte/short/char 移位后自动升为 int,小心隐式类型转换
如果你写
,表面上看没问题,但中间过程是:
先被提升为
,再左移,结果也是
。这在组合位运算时极易引发意料外的符号扩展或高位污染。
→
,不是
!因为
提升为
后是
,左移 1 变成
(256),但若你误以为它还是 byte 范围,就错了
想保持低位字节操作?显式用
截断,或直接用
/
避免符号干扰
涉及多个小整型拼包(如协议解析)时,优先统一用
或
,避免反复 cast
最常被忽略的一点:移位数本身不参与类型推导,它必须是
或可隐式转为
的类型;而左操作数类型直接决定“取多少位做移位计数”——这个规则藏在 IL 层,运行时不会报错,只会静默截断。写位运算前,先盯住两个操作数的类型。
<<>>i << 33i << 1iint10000100001i << 33i << 1intuintrightOperand & 0x1FlongulongrightOperand & 0x3Fchecked>>>>-8 >> 1-411111000 >> 1 → 11111100-1 >> 3-1(uint)x >> n(ulong)x >> n>>byte b = 1; int x = b << 2;bintintbyte b = 0b1000_0000; int r = b << 1;r == -256256bint0x000000800x00000100(byte)(b << 2)ushortuintuintintintint