所有的按位操作符的操作数都会被转成补码(two's complement)形式的有符号32位整数。正数的补码是自己本身,负数的补码是取反后加一,所以经过操作运算后的值是补码形式。

描述

  • 按位与( AND) a & b 对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
  • 按位或(OR) a | b 对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
  • 按位异或(XOR) a ^ b 对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
  • 按位非(NOT) ~ a 反转操作数的比特位,即0变成1,1变成0。
  • 左移(Left shift) a << b 将 a 的二进制形式向左移 b (< 32) 比特位,右边用0填充。
  • 有符号右移 a >> b 将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位。
  • 无符号右移 a >>> b 将 a 的二进制表示向右移 b (< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。

AND

a

b

a AND b

0

0

0

0

1

0

1

0

0

1

1

1

8 & 9 
=>
0000 0000, 0000 0000, 0000 0000, 0000 1000
0000 0000, 0000 0000, 0000 0000, 0000 1001
=>
0000 0000, 0000 0000, 0000 0000, 0000 1000
=> 
8
-8 & 9
=> 
1111 1111, 1111 1111, 1111 1111, 1111 1000 // -8 的补码
0000 0000, 0000 0000, 0000 0000, 0000 1001
=>
0000 0000, 0000 0000, 0000 0000, 0000 1000
=>
8

OR

a

b

a OR b

0

0

0

0

1

1

1

0

1

1

1

1

8 & 9 
=>  
0000 0000, 0000 0000, 0000 0000, 0000 1000
0000 0000, 0000 0000, 0000 0000, 0000 1001
=>
0000 0000, 0000 0000, 0000 0000, 0000 1001
=> 
9
-8 & 9
=> 
1111 1111, 1111 1111, 1111 1111, 1111 1000 // -8 的补码
0000 0000, 0000 0000, 0000 0000, 0000 1001
=>
11111111,11111111,11111111,11111001 // 补码
=>
11111111,11111111,11111111,11111000 // 反码
=>
10000000,00000000,00000000,00000111 //原码
=>
-7

XOR

a

b

a XOR b

0

0

0

0

1

1

1

0

1

1

1

0

8 & 9 
=>  
0000 0000, 0000 0000, 0000 0000, 0000 1000
0000 0000, 0000 0000, 0000 0000, 0000 1001
=>
0000 0000, 0000 0000, 0000 0000, 0000 0001
=> 
1
-8 & 9
=> 
1111 1111, 1111 1111, 1111 1111, 1111 1000 // -8 的补码
0000 0000, 0000 0000, 0000 0000, 0000 1001
=>
1111 1111, 1111 1111, 1111 1111, 1111 0001 // 补码
=>
1111 1111, 1111 1111, 1111 1111, 1111 0000 // 反码
=>
1000 0000, 0000 0000, 0000 0000, 0000 1111 //原码
=>
-15

NOT

a

NOT a

0

1

1

0

~ 8
=> 
0000 0000, 0000 0000, 0000 0000, 0000 1000 // 补码
=> 
1111 1111, 1111 1111, 1111 1111, 1111 0110 // 反码
=>
1000 0000, 0000 0000, 0000 0000, 0000 1001 // 原码
=>
-9
~-8
=>
1111 1111, 1111 1111, 1111 1111, 1111 1000 // -8 的补码
=>
0000 0000, 0000 0000, 0000 0000, 0000 0111 // not 8 补码,反码,原码
=>
7

左移

按位移动会先将操作数转换为大端 (big-endian) 表示的 32位整数,

该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。

8 << 3
=>
0000 0000, 0000 0000, 0000 0000, 0000 1000
=>
0000 0000, 0000 0000, 0000 0000, 0100 0000
=>
64
-8 << 3
=>
1111 1111, 1111 1111, 1111 1111, 1111 1000
=>
1111 1111, 1111 1111, 1111 1111, 1100 0000
=>
1111 1111, 1111 1111, 1111 1111, 1011 1111
=>
1000 0000, 0000 0000, 0000 0000, 0100 000
=>
-64

右移

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。

8 >> 3
=>
0000 0000, 0000 0000, 0000 0000, 0000 1000
=>
0000 0000, 0000 0000, 0000 0000, 0000 0001
=>
1
-8 >> 3
=>
1111 1111, 1111 1111, 1111 1111, 1111 1000
=>
1111 1111, 1111 1111, 1111 1111, 1111 1111
=>
1111 1111, 1111 1111, 1111 1111, 1111 1110
=>
1000 0000, 0000 0000, 0000 0000, 0000 001
=>
-1

无符号右移

该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。即便右移 0 个比特,结果也是非负的?

8 >>> 3
=>
0000 0000, 0000 0000, 0000 0000, 0000 1000
=>
0000 0000, 0000 0000, 0000 0000, 0000 0001
=>
1
-8 >>> 3
=>
1111 1111, 1111 1111, 1111 1111, 1111 1000
=>
0001 1111, 1111 1111, 1111 1111, 1111 1111
=>
0001 1111, 1111 1111, 1111 1111, 1111 1110
=>
0110 0000, 0000 0000, 0000 0000, 0000 001
=>
805306369

用途

想想看linux的文件权限就是这样做到的。简单的数字就可以表示你有什么权限。比如我们有4个状态,A,B,C,D,分别用二进制保存

  • A 0001=> 1
  • B 0010 => 2
  • C 0100 => 4
  • D 1000 => 8

如果你的状态是 A+B+C 那么你的权值就是 (A | B | C ) => 0111 => 7。这个时候做状态判断是就好做了。用D的值和你按位与下,看看值是否为1,就知道你有没有对应的权限

if(8 & your_status){
  // your have status
}else{
  // your don't have status
}