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<
2.比如说让一个数的第四位清零。 我们只需把第4位 &上0 即可。
x & 0b 1110 1111
x & 0x ef
因为构造某一位为0,我们需要给其他位填充1。我们有一种更通用的做法。
~0 便是0xfffffffffffffffff 位数就看变量的类型了,跳一步直接用i表示,我们可以得出下面的式子
x &= ~ 0x0010
x &= ~ (1<
3.测试第4位是否为1
if( x & 0x0010 ){ 操作 }
==>
if( x & (1<
这里就归纳一个宏出来
#define GetBit(dat,i) ( (dat)&( 0x1<
#define SetBit(dat,i) ( (dat)|=( 0x1<
#define ClearBit(dat,i) ( (dat)&= ~( 0x01<
这里没有考虑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 <
}
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;
}