位运算包括与,或,取反,异或,左移,右移等。编程
一 位运算计算数据结构
1 与运算:&函数
操做符&将2个数的二进制位进行与操做,2个数对应的位都为1,运算结果为1;不然运算结果为0。设计
好比 6&8,6的二进制为:0110 8的二进制为:1000。因此6&8 = 0000 = 0指针
2 或运算:|blog
操做符|将2个数的二进制位进行或操做,2个数对应的位有一个为1,运算结果为1;不然运算结果为0。it
好比 6&8,6的二进制为:0110 8的二进制为:1000。因此6&8 = 1110 = 14io
3 取反运算:~效率
操做符~将每位二进制位取反,1变0,0变1。变量
好比 ~6,6的二进制位为0110,~6 = ~0110 = 1001 = 9
4 异或:^
操做符^将2个数的每一个二进制位异或,2个数对应的位相同,运算结果为0,不然运算结果为1。
好比 6^10,6的二进制为0110,9的二进制为1010, 0110^1010 = 1100 = 12
5 右移运算符:>> 右移运算分二种:逻辑右移和算术右移
①逻辑右移
逻辑右移在移动过程当中,左边位用0填充。好比1000 0011右移3位,变成0001 0000
②算术右移
算术右移在移动过程当中,左边位用符号位填充。好比1000 0011右移3位,变成1111 0000
6 左移运算符:<<
左移过程当中,右边一概用0填充。0000 1100左移2位为0011 0000
在实际的编程过程当中,每每会用一个整数的不一样位表示不一样的数据信息。在访问该整数时,就须要经过位运算来得到或者改变整数的某几位数值。好比在Windows中建立文件时使用的Create数据结构:
struct
{
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT FileAttributes;
USHORT ShareAccess;
ULONG POINTER_ALIGNMENT EaLength;
PVOID EaBuffer;
LARGE_INTEGER AllocationSize;
} Create;
一般会引用其中的Options以下:
Data->Iopb->Parameters.Create.Options
ULONG Options是一个Windows文件建立过程当中的无符号长整数,指示在建立和打开文件时的不一样选项。其中高8位指示了CreateDisposition参数(如FILE_OPEN,FILE_CREATE),低24位指示了CreateOptions参数(如FILE_DELETE_ON_CLOSE)。 为了获得CreateDisposition的值,采起下面的位操做:
(Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff;
将该整数右移24位,再与0xff作与操做,便可得到CreateDisposition的值。
二 位运算应用
a^0=a
a^a=0
利用上述性质,能够用来计算2个数的交换。
你们应该知道,在计算机里,两个数互相交换,须要定义一个中间的变量来参与交换。如:
int tmp;
int a=10;
int b=20;
tmp=a;
a=b;
b=tmp;
上述代码计算以后,a和b的值完成交换,a的值为20,b的值为10。
若是用异或运算来交换2个数,能够以下方法:
int a=10;
int b=20;
a=a^b;
b=a^b;
a=a^b;
上述运行以后,a和b依然完成了值的交换,但因为是异或位运算,因此效率比上面的代码要高。
证实:
a=10^20
b=a^b=(10^20)^20=10^20^20=10^0=10
a=a^b=10^20^10=10^10^20=0^20=20
把上述代码,能够封装为一个交换2个数的函数以下:
void swap(int *a, int *b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
或者用宏来定义:
#define SWAP(a,b) \
do { \
a = a^b; \
b = a^b; \
a = a^b; \
} while(0)
但按照下面的方法来写一个函数,试着将两个数进行交换,是错误的(想一想为何?)
void swap(int a, int b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
#define BITN (1《n)
置位:a |= BITN;
清零:a &= ~BITN
方法:a & (a – 1)//该运算将会清除掉整数a二进制中最右边的1。
问题:如何判断判断整数x的二进制中含有多少个1?
分析:此题是微软公司的一道笔试题。下面用&运算来解决此题。 代码以下:
int func(int x )
{
int countx = 0;
while ( x )
{
countx++;
x = x&(x-1);
}
return countx;
}
提示:
要实现该设计要求,须要记住链表的头结点和尾结点,并在链表结点的的next域存放前一个结点和后一个结点的异或值。即:
p->next=pl^pr;//头结点的左边结点为NULL,尾结点的右边结点为NULL。
在遍历的时候,从头结点往右遍历的方法:
pl=NULL;
p=Head;
while(p!=Tail)
{
pr=pl^(p->next);
pl=p;
p=pr;
}
从尾结点往左遍历的方法:
pr=NULL;
p=Tail;
while(p!=Tail)
{
pl=pr^(p->next);
pr=p;
p=pl;
}
(char)(127<<1)+1(char)(-1>>1)+11<<2+3解答:(char)(127<<1)+1=(01111111<<1)+1=11111110+1=11111111=-1(char)(-1>>1)+1=(11111111>>1)+1=11111111+1=01<<2+3=1<<(2+3)=1<<5=2^5=32(注意《和+的优先级)