C语言位操作基础详解与实战

1、位与&
      1)“位与”:&   “逻辑与”:&&
      2)  真值表:1&0 = 0  、0&1 = 0、0&0 = 0、1&1 = 1         只有当1与1位与时才是1,其他的值相与都是0
      3)“位与”就是把2个十六进制的数先分别转换为二进制,然后再相与。“逻辑与”就是把2个十六进制分别看成2个整体,2个整体相与。
              例子:0xA & 0xB = 0xA   //位与                               0xA && 0xB = 1 //逻辑与
                          0xA:1 0 1 0                                                   0xA = 1 (ture)
                          0xB:1 0 1 1                                                   0xB = 1 (ture)
                          位与: 1 0 1 0                                                    逻辑与 : 1

2、位或|
     1)“位或”:|    “逻辑或”:||
     2)  真值表:1|0 = 1  、0|1 = 1、0|0 = 0、1|1 = 1           只有两个0位或的时候才是0,其余的都是1
     3)  “位或”就是把2个十六进制的数先分别转换为二进制,然后再位或;“逻辑或”就是把2个十六进制分别看成2个整体,2个整体位或。
               例子:0xA | 0xB = 0xB                                                 0xA || 0xB = 1
                           0xA:1 0 1 0                                                      0xA = 1 (ture)
                           0xB:1 0 1 1                                                      0xB = 1 (ture)
                            位或: 1 0 1 1                                                      逻辑或 : 1

3、位取反 ~

     1)“位取反”:~     “逻辑取反”:!
     2)“位取反”就是把十六进制数先转换为二进制,然后把每一位取反(1取反就变为0,0取反就为1);“逻辑取反”就是把十六进制数看成一个整体,然后取反(非0的数都是为真,逻辑取反后为假;0逻辑取反为真)。
                3) 例子:0xA =  1 0 1 0                                                              0xA (非0为真(即1))
                    ~0xA =  0 1 0 1 = 0x5                                                              !0xA = 0
                   ~~0xA = 1 0 1 0 = 0xA                                                             !!0xA = 1    
    
4、位异或 ^
    1) “位异或”: ^  
    2) 真值表:1^0=1    0^1=1   0^0=0   1^1=0         两个数相等则为0,不相等则为1
    3) 例子: 66 ^ 33 = 99
                     66: 1 0 0 0 0 1 0
                     33: 0 1 0 0 0 0 1
                     99: 1 1 0 0 0 1 1

              代码:   unsigned int a = 66, b = 33;
                             unsigned int c = a^b;
                             printf("c = %d ", c);

5、左移位<<     右移位>>
        无符号数,左移时在右边补0,右移时在左边补0


二.位操作的实际应用

        一般在操作寄存器的时候使用,如32位的arm寄存器,每个位代表的pin脚不同,效果也不同。有时候你只想改变某个pin脚的值从而实现某项功能,其余pin脚保持不变,就得使用位操作,只对目标位进行操作。操作的方式是:读->改->写。不要直接给寄存器赋目标值是因为你只知道要把目标位设置为某值,但是其他的位你并不知道原本是多少,所以要先读取这个寄存器的整体值,然后再修改其中的目标位,然后再把修改后的值写到寄存器。

1)特定位清零用&
             譬如:将0xAAAAAAAA 的bit8 ~bit15清零,其他位保持不变。
             分析:[位与]任何数(0/1)与1位与时为本身,与0位与为0,所以可以用位与的方式。
                         unsigned int a = 0xAAAAAAAA;
                         unsigned int b = 0xFFFF00FF;
                         unsigned int c;
                         c = a & b;
                         printf("c = 0x%x ", c);    //c = 0xaaaa00aa

2)特定位 置1用 |
      譬如:将0xffff00ff的bit8 ~bit15置1,其他位保持不变。
      分析:位或   任何数(0/1)与1位或变为1,与0位或为本身

                  unsigned int a = 0xffff00ff;
                  unsigned int b = 0x000ff00;
                  unsigned int c;
                  c = a | b;
                  printf("c = 0x%x ", c);    // = 0xffffffff

3)特定位取反用 ^
      譬如:将0xffff00ff的bit8 ~bit15取反,其余保持不变
      分析:位异或  任何数(0/1)与1位异或会取反,与0位异或为本身
    
                  unsigned int a = 0xffff00ff;
                  unsigned int b = 0xff00;
                  unsigned int c;
                  c = a ^ b;
                  printf("c = 0x%x ", c);    // = 0xffffffff


三、特定二进制数的获取
       由于上面示例中的unsigned int b的值太过于呆板,后续看代码的时候可能不知道为什么是这个值,所以需要以另外的方式来表达(主要是通过位移和位取反来获取这个特定的二进制数)。

(1)    譬如:unsigned int b = 0xff00; 中的0xff00
         可表示为:0xFF<<8    (0xFF :8个二进制1   <<: 左移   8: 8位)

(2)    需要一个bit3 ~bit7,bit23~bit25为1的数(隐含意思是其他位都为0)
         可为:0x1F<<3 | 0x7<<23
                    1F (7-3+1=5个1,转换为十六进制则为1F);
                     7  ( 25-23+1=3个1,转换为十六进制则为7)
                      |  ( 位或,任何数与1位或都为1,与0位或为本身,所以这里用位或就相当于把这2个位移后的数叠加起来)

(3)    需要一个bit3 ~ bit7为0的数
         可为:~(0x1F<<3)

       总结:当需要的1比较少,需要的0比较多,就使用1位移的方式;当需要的0比较少,需要的1比较多,就使用位移然后取反的方式;当需要的数比较复杂,如bit3 ~bit7,bit23~bit25为1,就可以先位移然后位或的方式。

你可能感兴趣的:(C,C语言,位操作,基础,实战)