linux位操作

来源:互联网 发布:内江恒迈网络 编辑:程序博客网 时间:2024/06/09 19:23
Linux内核提供了一些对位操作的方法:

include/asm-generic/bitops/atomic.h
[cpp] view plaincopyprint?
  1. void set_bit(int nr, volatile unsigned long *addr)  
  2. void clear_bit(int nr, volatile unsigned long *addr)  
  3. void change_bit(int nr, volatile unsigned long *addr)  
  4. int test_and_set_bit(int nr, volatile unsigned long *addr)  
  5. int test_and_clear_bit(int nr, volatile unsigned long *addr)  

上面的这些方法都是原子操作的。


void set_bit(int nr, volatile unsigned long *addr)
将存放在addr内存地址的unsigned long类型的数据的nr位设成1。这儿改变的是addr地址的数据的相应位,而这个数据的类型为unsigend long。参数nr是可以大于unsigend long的bit的位数(一般为0~31)。假设传入的nr为33,那么修改的就是addr+1地址的数据的第1位(从第0位开始计算)。


void clear_bit(int nr, volatile unsigned long *addr)
将相应位设成0。


void change_bit(int nr, volatile unsigned long *addr)
将相应位置反。


int test_and_set_bit(int nr, volatile unsigned long *addr)
将相应位设成1,并返回未设置之前的值。如果之前的值为0,返回0,如果之前的值为1,返回真(非0,可能是1,也可能是-1,跟平台有关)。


int test_and_clear_bit(int nr, volatile unsigned long *addr)
将相应位设成0,并返回未设置之前的值。


Linux还提供了一些非原子操作的方法:

include/asm-generic/bitops/no-atomic.h
[cpp] view plaincopyprint?
  1. void __set_bit(int nr, volatile unsigned long *addr)  
  2. void __clear_bit(int nr, volatile unsigned long *addr)  
  3. void __change_bit(int nr, volatile unsigned long *addr)  
  4. int __test_and_set_bit(int nr, volatile unsigned long *addr)  
  5. int __test_and_clear_bit(int nr, volatile unsigned long *addr)  
  6. int __test_and_change_bit(int nr,volatile unsigned long *addr)  
  7. int test_bit(int nr, const volatile unsigned long *addr)  


int test_bit(int nr, const volatile unsigned long *addr)
检测相应位的值,如果相应位为0,则返回假;如果相应位为1,则返回真。


除了上面一些操作外,经常还会遇到一些与位相关的宏:

include/linux/bitops.h
[cpp] view plaincopyprint?
  1. #define BIT(nr)(1UL << (nr))  
  2. #define BIT_MASK(nr)(1UL << ((nr) % BITS_PER_LONG))  
  3. #define BIT_WORD(nr)((nr) / BITS_PER_LONG)  
  4. #define BITS_PER_BYTE8  
  5. #define BITS_PER_LONG        (sizeof(long) * BITS_PER_BYTE)  
  6. #define BITS_TO_LONGS(nr)DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))  
  7. #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))  

BIT(nr)与BIT_MASK(nr)的效果一样,都是将nr位置1。不同的是当nr大于等于long型所占用的位数时,BIT(nr)返回0。例如,一个long占32位,那么BIT(32)=0,BIT_MASK(32)=1。


BIT_WORD(nr)
BITS_TO_LONGS(nr)
上面两个宏都表示:一个数占用nr位,那么这个数就需要BITS_TO_LONGS(nr)个long型数据来表示。比如,long型数据占用32位。BITS_TO_LONGS(0)=0,BITS_TO_LONGS(1~32)=1。
DIV_ROUND_UP(n,d)
返回n/d的最小整数。


还有下面几个:

fls(unsigned count);
当count为0时,fls(0)返回0。
当count>0时,fls(count)返回将count转换成二进制后,从高位到低位第一个为1的位数(从0开始计算)+1。
比如,fls(1)=1,fls(2) = 2 ,fls(3)=2 ,fls(4)=3, fls(5)=3。


get_count_order(unsigned count);
返回log2count。如果log2count不是整数,那么返回大的整数。
如:当count为1时,返回0,当count为2时,返回1,当count为3~4时,返回2,当count为5~8时,返回3。


判断一个数count是否为2的指数的方法:
count&(count-1)
如果count是2的指数,那么上面与运算结果为0,否则不为0。内核中使用下面方法。

include/linux/log2.h
[cpp] view plaincopyprint?
  1. bool is_power_of_2(unsigned long n)  
  2. {  
  3.     return (n != 0 && ((n & (n - 1)) == 0));  
  4. }  
lib/find_next_bit.c
[cpp] view plaincopyprint?
  1. unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)  

在以addr开始的内存区中查找第一个值为0的位,查找范围为size大小。
addr为内存区的起始地址,size为要查找的最大长度。
返回第一个位为0的位号。如果没找到,则返回值大于size。
在内存当中从addr为起始地址,以size为最大的搜索范围寻找第一个是0的bit位,并且返回该bit位的bit位号(从0开始计算)。该方法用于取得一个long型数据的最低0位。
如:unsigned long data = 0x5f,则find_first_zero_bit(&data,sizeof(data)) = 5。

0 0
原创粉丝点击