C语言位操作

C语言提供6个按位操作


<< 左移      右端补零,操作的对象是 任意 int char   这里任意是指有无符号的意思。
>> 右移      无符号数或者是正数不用考虑是左端补0, 负数看实现【一些实现补0,一些保留符号位,这种比较科学吧】
~   按位取反   【一元运算符】
&   按位与
^   按位异或
|    按位或

为了保证可移植性,寄存器当然用unsinged char 或者unsinged int ,当然更详细一点的posix标准里的
1字节     uint8_t
2字节     uint16_t
4字节     uint32_t
8字节     uint64_t
当然有符号的就是 int8_t 这样的表示。

那么 一元运算符是什么意思呢?
  int i = ~k;   //操作是数只有自己啊
  int i = a&b; //这样才是二元

按位很好理解就是每一位都操作一下,比如  a =0b11111001    b=0b00001110
例子:a & b 
        1111 1001
&     0000 1110
       ----------------
        0000 1000
这四个符号的优先级:~    &    ^   |
避免歧义就不要吝啬括号 ,当然看了半天,想到还有 ||   &&   这个操作是逻辑操作,结果是0 或者1,和这个不太一样。

最常用的三种操作


1.设置位
2.清楚位
3.测试位

      假设我们的一个8位寄存器保存在unsigned char  x 中。[0-7位]
     1.比如说让一个数的第四位设置为1。 我们只需把第4位 或(|)上1 即可.
          x |=  0b0001 0000
          x |=  0x0100
         为了更通用的写法,我们通常把第几位当成一个变量i 
          x |=  (1<<i )
         
     2.比如说让一个数的第四位清零。 我们只需把第4位 &上0 即可。
          x & 0b 1110 1111
          x & 0x  ef
          因为构造某一位为0,我们需要给其他位填充1。我们有一种更通用的做法。
          ~0 便是0xfffffffffffffffff 位数就看变量的类型了,跳一步直接用i表示,我们可以得出下面的式子
          x &=   ~ 0x0010
          x &=  ~ (1<<i)

     3.测试第4位是否为1   
          if( x & 0x0010 ){  操作 }
          ==>
          if(   x &  (1<<i)  ){ 操作 }

这里就归纳一个宏出来

#define GetBit(dat,i)   (  (dat)&( 0x1<<(i) )?1:0    )
#define SetBit(dat,i)    (  (dat)|=( 0x1<<(i) ) )
#define ClearBit(dat,i) (  (dat)&=  ~( 0x01<<(i) )   )
这里没有考虑dat是什么类型,可以C语言的关键字获取到类型后,强转一下,效果应该更好。

内核的实现

extern __inline__ int set_bit(int nr,long * addr)
{  
    int mask, retval;
    addr += nr >> 5;             //(1)
    mask = 1 << (nr & 0x1f);  //(2)
    cli();
    retval = (mask & *addr) != 0;
    *addr |= mask;               //(3)
    sti();
    return retval;
}

假设*addr = 0, nr = 3;则执行结果为1000(二进制数)

(1)如果nr大于32,则addr移动(nr/32)位数,指向下一个long 的开始位。nr>>5也就是nr除以2的5次方,等于nr/32.    

(2)截取nr的低5位,然后将1左移(低5位对应的10进制数)。这样做是为了解决当nr大于31时,将1左移32位或者更多将会导致溢出(因为mask是int型,而int型在linux中是32位长)。
为什么特意截取nr的低5位呢,我认为是经验,你可以试试看,比如我传递给nr的值为33,则mask的值为  mask = 1 << (33 & 0x1f);   计算结果为mask=1<<1,mask=0x10,
另外说明一下:0x1f(16进制) = 11111(2进制) = 31(10进制)
对于1.2两部非常的佩服,统一了是否移位大于32位的操作
感觉指针运用的炉火纯青,关于x位处理器long的实现应该是x位吧。

通过步骤1我们知道addr指向32位的位置,那么 (*addr |= mask)就会把第33位置1了。


多位的操作

1.连续修改多位

     首先用按位与清除
     使用按位或存入
     比如将101(0x5) 存入 4-6位
     i=(i & ~0x70 )|( 0x5 >>4)
       这里还需要归纳一下 0x70 因为是清理3位 那么 0x7左移动4位
      i= (i & ~(0x7 >>4)  | 0x5 >>4)
     那么我们只需要清理几位,放到第几位(最低位),和存入的值 即可。

#define setNbit(dat,N,low_index,value){ \
     int mask=0,i=N;   \
     while(--i>=0){   \
              mask |= (0x1<< i );\
     } \
   (dat) =   ( (dat) &  ~( mask <<(low_index)  )  | ((value) <<(low_index)) ); \
}

2.连续获取多位

     例:获取 3-5位
     移位到最位数最右端,然后取N位
    ( i >>3 ) &0x7
#define getNbit(dat,N,low_index,value){\
     int mask=0,i=N; \
     while(--i>=0){ \
              mask |= (0x1<< i ); \
     }\
   value = ( (dat)>>(low_index) &(mask) );\
}
感觉这种宏的实现有点蹩脚,还是用函数实现比较看起来爽一点。
void setNbit(unsigned *dat, int N, int low_index, int value)
{
        int mask = 0, i = N;
        while (--i >= 0)
        {
                mask |= (0x1 << i);
        }
        *dat = *dat & (~(mask << low_index)) | (value << low_index);
}




void getNbit(unsigned *dat, int N, int low_index, int *value)
{
        int mask = 0, i = N;
        while (--i >= 0)
        {
                mask |= (0x1 << i);
        }
        *value = (*dat >> low_index) & mask;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值