13.位运算符.md 4.1 KB
Newer Older
极客江南's avatar
极客江南 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
## 位运算符

- 程序中的所有数据在计算机内存中都是以二进制的形式储存的。
- 位运算就是直接对整数在内存中的二进制位进行操作
- C语言提供了6个位操作运算符, 这些运算符只能用于整型操作数

| 符号 | 名称     | 运算结果     |
| ---- | -------- | ------------ |
| &    | 按位与   | 同1为1       |
| \|   | 按位或   | 有1为1       |
| ^    | 按位异或 | 不同为1      |
| ~    | 按位取反 | 0变1,1变0    |
| <<   | 按位左移 | 乘以2的n次方 |
| >>   | 按位右移 | 除以2的n次方 |

------

- 按位与:
  - 只有对应的两个二进位均为1时,结果位才为1,否则为0
  - 规律: 二进制中,与1相&就保持原位,与0相&就为0

```
9&5 = 1

 1001
&0101
------
 0001
```

------

- 按位或:
  - 只要对应的二个二进位有一个为1时,结果位就为1,否则为0

```c
9|5 = 13

 1001
|0101
------
 1101
```

------

- 按位异或
  - 当对应的二进位相异(不相同)时,结果为1,否则为0
  - 规律:
    - 相同整数相的结果是0。比如55=0
    - 多个整数相^的结果跟顺序无关。例如: 567=576
    - 同一个数异或另外一个数两次, 结果还是那个数。例如: 577 = 5

```c
9^5 = 12

 1001
^0101
------
 1100
```

------

- 按位取反
  - 各二进位进行取反(0变1,1变0)

```c
~9 =-10
0000 0000 0000 0000 0000 1001 // 取反前
1111 1111 1111 1111 1111 0110 // 取反后

// 根据负数补码得出结果
1111 1111 1111 1111 1111 0110 // 补码
1111 1111 1111 1111 1111 0101 // 反码
1000 0000 0000 0000 0000 1010 // 源码 == -10
```

------

- 位运算应用场景:

  - 判断奇偶(按位或)

  ```c
     偶数: 的二进制是以0结尾
     8   -> 1000
     10  -> 1010
     
     奇数: 的二进制是以1结尾
     9   -> 1001
     11  -> 1011
  
     任何数和1进行&操作,得到这个数的最低位
     1000
    &0001
     -----
     0000  // 结果为0, 代表是偶数
  
     1011
    &0001
     -----
     0001 // 结果为1, 代表是奇数
  ```

  - 权限系统

  ```c
    enum Unix {
      S_IRUSR = 256,// 100000000 用户可读
      S_IWUSR = 128,//  10000000 用户可写
      S_IXUSR = 64,//    1000000 用户可执行
      S_IRGRP = 32,//     100000 组可读
      S_IWGRP = 16,//      10000 组可写
      S_IXGRP = 8,//        1000 组可执行
      S_IROTH = 4,//         100 其它可读
      S_IWOTH = 2,//          10 其它可写
      S_IXOTH = 1 //           1 其它可执行
     };
  // 假设设置用户权限为可读可写
  printf("%d\n", S_IRUSR | S_IWUSR); // 384 // 110000000
  ```

  - 交换两个数的值(按位异或)

  ```c
   a = a^b;
   b = b^a;
   a = a^b;
  ```

------

- 按位左移
  - 把整数a的各二进位全部左移n位,高位丢弃,低位补0
    - 由于左移是丢弃最高位,0补最低位,所以符号位也会被丢弃,左移出来的结果值可能会改变正负性
  - 规律: 左移n位其实就是乘以2的n次方

```c
2<<1; //相当于 2 *= 2 // 4
  0010
<<0100

2<<2; //相当于 2 *= 2^2; // 8
  0010
<<1000
```

- 按位右移
  - 把整数a的各二进位全部右移n位,保持符号位不变
    - 为正数时, 符号位为0,最高位补0
    - 为负数时,符号位为1,最高位是补0或是补1(取决于编译系统的规定)
  - 规律: 快速计算一个数除以2的n次方

```c
2>>1; //相当于 2 /= 2 // 1
  0010
>>0001
4>>2; //相当于 4 /= 2^2 // 1
  0100
>>0001
```

- 练习:
  - 写一个函数把一个10进制数按照二进制格式输出

```c
#include <stdio.h>
void printBinary(int num);
int main(int argc, const char * argv[]) {
    printBinary(13);
}
void printBinary(int num){
    int len = sizeof(int)*8;
    int temp;
    for (int i=0; i<len; i++) {
        temp = num; //每次都在原数的基础上进行移位运算
        temp = temp>>(31-i); //每次移动的位数
        int t = temp&1; //取出最后一位
        if(i!=0&&i%4==0)printf(" "); printf("%d",t);
    }
}
```

## 

最后,如果有任何疑问,请加微信 **leader_fengy** 拉你进学习交流群。

开源不易,码字不易,如果觉得有价值,欢迎分享支持。