位操作

Linux内核提供了一些对位操作的方法:

include/asm-generic/bitops/atomic.h
void set_bit(int nr, volatile unsigned long *addr)
void clear_bit(int nr, volatile unsigned long *addr)
void change_bit(int nr, volatile unsigned long *addr)
int test_and_set_bit(int nr, volatile unsigned long *addr)
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
void __set_bit(int nr, volatile unsigned long *addr)
void __clear_bit(int nr, volatile unsigned long *addr)
void __change_bit(int nr, volatile unsigned long *addr)
int __test_and_set_bit(int nr, volatile unsigned long *addr)
int __test_and_clear_bit(int nr, volatile unsigned long *addr)
int __test_and_change_bit(int nr,volatile unsigned long *addr)
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
#define BIT(nr)(1UL << (nr))
#define BIT_MASK(nr)(1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr)((nr) / BITS_PER_LONG)
#define BITS_PER_BYTE8
#define BITS_PER_LONG        (sizeof(long) * BITS_PER_BYTE)
#define BITS_TO_LONGS(nr)DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#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
bool is_power_of_2(unsigned long n)
{
    return (n != 0 && ((n & (n - 1)) == 0));
}
lib/find_next_bit.c
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。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值