csharp 中 int 、uint、long 、ulong 可以直接参与位运算, 对于 sbyte 、byte 、short、ushort、char 类型则先转换成 int 来参与位运算。如果操作数是不同类型的,则转换成距离二者最近的类型参与运算, 转换规则可以参看 数值提升。
位运算符有:
- 按位取反
~
- 左移
<<
、右移>>
, 也被称为算术位移 - 无符号右移
>>>
, 也被称为逻辑位移, 在 c# 11.0 以上可 #csharp11 - 与
&
、或|
、异或^
位移运算规则
为了便于描述, 做出以下说明:
- a 为移位的对象
- c 为移位的位数
- bitwidth 为 a 在内存中占据的 bit 位宽, 假如 a 是 int 类型, 则占据 32 位宽
a 以连续 0/1 串的形式存储在内存中, 可以将占有的内存片段称为内存盒子。无论左移还是右移, 等价于整体向一个方向移动, 内存盒子出现空位, 空位会被填上 0 或者 1, 移出存储盒子的位则被抛弃。注意:实际运算并不存在位的移动, 只是为了方便理解进行的形象化描述。当所有的位移出存储盒子, 则恢复为原来的值, 所以位移具有周期性, 周期为 bitwidth。
左移
左移操作, 存储盒子右侧出现空位, 并且填充 0, 移动 bitwidth - 1
次, 最右侧的位移动到最左侧, 再移动一次则恢复最初的值, 如此往复。
右移
逻辑位移和算术位移在空位填补上存在区别, 正数和负数的空位填补上存在区别。
正数
算术位移和逻辑位移的行为一致。存储盒子左侧出现空位, 并且用 0 填充, 移动 bitwidth - 1
次, 最高位移动到最低位。再移动一次则恢复最初的值, 如此往复。
负数
算术位移和逻辑位移的行为有区别。存储盒子左侧出现空位, 逻辑位移使用 0 来填充, 算术位移用 1 。移动 bitwidth - 1
次, 最高位移动到最低位。再移动一次则恢复最初的值, 如此往复。
复合赋值
位移操作通用支持符合复制。形如 x op= y
等价于 x = x op y
, op 可以是&
、|
、^
、>>
、<<
、>>>
枚举逻辑运算符
所有枚举类型还支持 ~、&、| 和 ^ 运算符。 对于相同枚举类型的操作数,对底层整数类型的相应值执行逻辑运算。 例如,对于具有底层类型 U 的枚举类型 T 的任何 x 和 y,x & y 表达式生成与 (T)((U)x & (U)y) 表达式相同的结果。