位運算包括與,或,取反,異或,左移,右移等。編程
一 位運算計算數據結構
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(注意《和+的優先級)