1. 位逻辑运算符

4个位运算符用于整型数据,包括char,将这些位运算符成为位运算的原因是它们对每位进行操作,而不影响左右两侧的位。请不要将这些运算符与常规的逻辑运算符(&& 、||、!)相混淆,常规的位的逻辑运算符对整个值进行操作。

1.1. 按位取反:~

一元运算符~将每个1变为0,将每个0变为1,如下面的例子:

  1. ~(10011010)
  2. ==01100101

假设 a 是一个 unsigned char,已赋值为2. 在二进制中,2是00000010.于是 -a 的值为11111101或者253。请注意该运算符不会改变a的值,a仍为2。

1.2. 位与(AND): &

二进制运算符&通过对两个操作数逐位进行比较产生一个新值。对于每个位,只有两个操作数的对应位都是1时结果才为1。

  1. (10010011)
  2. & (00111101)
  3. ==(00010001)

C 也有一个组合的位与 - 赋值运算符:&=。下面两个将产生相同的结果:

  1. val &= 0377;
  2. val = val & 0377;

1.3. 位或(OR): |

二进制运算符|通过对两个操作数逐位进行比较产生一个新值。对于每个位,如果其中任意操作数中对应的位为1,那么结果位就为1.

  1. (10010011)
  2. | (00111101)
  3. == (10111111)

C也有组合位或-赋值运算符: |=

  1. val |= 0377;
  2. val = val | 0377;

1.4. 位异或:

二进制运算符^对两个操作数逐位进行比较。对于每个位,如果操作数中的对应位有一个是1(但不是都是1),那么结果是1.如果都是0或者都是1,则结果位0.

  1. (10010011)
  2. ^ (00111101)
  3. = (10101110)

C也有一个组合的位异或-赋值运算符: ^=

  1. val ^= 0377;
  2. val = val ^ 0377;

1.5 用法

1.5.1 打开位

已知:flag = 0b10011010

  1. 将位2打开
    1. (10011010)
    2. | (00000100)
    3. = (10011110)
  1. 将所有位打开。
    1. // flag | ~flag
    2. (10011010)
    3. | (01100101)
    4. = (11111111)

1.5.2 关闭位

  1. // flag & ~flag
  2. (10011010)
  3. & (01100101)
  4. = (00000000)

1.5.3 转置位

转置(toggling)一个位表示如果该位打开,则关闭该位;如果该位关闭,则打开。您可以使用位异或运算符来转置。其思想是如果b是一个位(1或0),那么如果b为1则b^1为0,如果b为0,则1^b为1。无论b的值是0还是1,0^b为b.

  1. // flag ^ 0xff
  2. (10010011)
  3. ^ (11111111)
  4. = (01101100)

1.5.4 交换两个数不需要临时变量

  1. //a ^ b = temp;
  2. //a ^ temp = b;
  3. //b ^ temp = a
  4. (10010011)
  5. ^(00100110)
  6. =(10110101)
  7. (10110101)
  8. ^(00100110)
  9. = 10010011
  10. int a = 10;
  11. int b = 30;

2 移位运算符

现在让我们了解一下C的移位运算符。移位运算符将位向左或向右移动。同样,我们仍将明确地使用二进制形式来说明该机制的工作原理。

2.1 左移 <<

  1. a = 0b00101101; // 45
  2. b = 0b00010111; // 23
  3. a ^ b == 0b00111010
  4. a = 0b00101101
  5. (a ^ b) ^ a == 0b00010111

左移运算符<<将其左侧操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出来的位用0填充,并且丢弃移出左侧操作数末端的位。在下面例子中,每位向左移动两个位置。

  1. (10001010) << 2
  2. (00101000)

该操作将产生一个新位置,但是不改变其操作数。

  1. 1 << 1 = 2;
  2. 2 << 1 = 4;
  3. 4 << 1 = 8;
  4. 8 << 2 = 32;

2.2 右移 >>

右移运算符>>将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。丢弃移出左侧操作数有段的位。对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端)位的副本填充。

  1. //有符号值
  2. (10001010) >> 2
  3. (00100010) //在某些系统上的结果值
  4. (10001010) >> 2
  5. (11100010) //在另一些系统上的结果
  6. //无符号值
  7. (10001010) >> 2
  8. (00100010) //所有系统上的结果值

2.3 用法:移位运算符

移位运算符能够提供快捷、高效(依赖于硬件)对2的幂的乘法和除法。

number << n number乘以2的n次幂
number >> n 如果number非负,则用number除以2的n次幂