c語言中位運算子及用法
位 運 算
一直對位運算頭疼,在此總結一下程式中的所有數在計算機記憶體中都是以二進位制的形式儲存的。位運算說穿了,就是直接對整數在記憶體中的二進位制位進行操作。運位算包括位邏輯運算和移位運算,位邏輯運算能夠方便地設定或遮蔽記憶體中某個位元組的一位或幾位,也可以對兩個數按位相加等;移位運算可以對記憶體中某個二進位制數左移或右移幾位等。
計算機內部是以補碼形式存放數值的。
C語言提供了六種位運算
位運算子 | 含義 | 舉例 |
&(and) | 按位與 | a&b |
| ( or ) | 按位或 | a|b |
^ ( xor ) | 按位異或 | a^b |
~ ( not ) | 按位取反 | ~a |
<< ( shi ) | 左移 | a<<1 |
>> ( shr ) | 右移 | a>>1 |
位邏輯運算規則
a | b | a&b | a|b | a^b | ~a | ~b |
0 | 0 | 0 | 0 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 0 | 0 | 0 |
假設a,b為整型的資料,並且設a=15(等於二進位制數00000000 00001111),b=80(等於二進位制數 00000000 01010000)
a的補碼:00000000 00001111
b的補碼:00000000 01010000
————————
a&b: 00000000 00000000 a&b=0x0
a|b : 00000000 01011111 a|b=0x5f
a^b : 00000000 01011111 a^b=0x5f
~a : 11111111 11110000 ~a=0xfff0
位運算應用口訣
清零取反要用與,某位置一可用或
若要取反和交換,輕輕鬆鬆用異或
1.“按位與”運算子&
運算規則:參加運算的兩個運算量,如果兩個數相應位的值都是1,則該位的結果值為1,否則為0。即:0 & 0 =0;0 & 1 =0;1 & 0 =0;1 & 1 =1。
(1)將某些二進位制位遮蔽掉(保留一個數據中的某些位)。
如果要使整數k的低四位置零,保留其它位。用位與運算即可,將的高位元組與0相與,低位元組與1相與;
程式碼如下:unsigned int_set(unsigned int k)
{k=k&0x1110;
Return(k);}
例】00101010 01010010&11111111 11110000=00101010 01010010。
結論:任何二進位制位與0能實現置0;與1保持原值不變
(2)判斷一個數據的某一位是否為1。
如判斷一個整數a(2個位元組)的最高位是否為1,可以設一個與a同類型的測試變數test,test的最高位為1,其餘位均為0,即int test=0x8000。
【例】 0100010011111110&1000000000000000=0 說明最高位為0;
1100010011111110&1000000000000000=1000000000000000 說明最高位為1;
例如一個數 and 1的結果就是取二進位制的最末位。這可以用來判斷一個整數的奇偶,二進位制的最末位為0表示該數為偶數,最末位為1表示該數為奇數.
2.“按位或”運算子|
常用來將源運算元某些位置1,其它位不變。 (mask中特定位置1,其它位為0 s=s|mask)
運算規則:參加運算的兩個運算量,如果兩個數相應位的值都是0,。即:0 | 0 =0;0 | 1 =1;1 | 0 =1;1 | 1 =1
把一個數據的某些位置為1。
如果把a的第10位置為1,而且不要破壞其它位,可以對a和b進行“按位或”運算,其中b的第10位置為1,其它位置為0,即int b=0x400。
【例】00100000 01010010|00000010 00000000=00100010 01010010。
3.“按位異或”運算子^
運算規則:參加運算的兩個運算量,如果兩個數的相應位的值不同,則該位的結果值為1,否則為0。即:0 ^ 0 =0;0 ^ 1 =1;1 ^ 0 =1;1 ^ 1 =0
應用舉例:
(1)把一個數據的某些位翻轉,即1變為0,0變為1。
如要把a的奇數位翻轉,可以對a和b進行“按位異或”運算,其中b的奇數位置為1,偶數位置為0,即int b=0xaaaa。
【例】a的補碼:00000000 01010010
b的補碼: 01010101 01010101
^ -------------------
結果的補碼: 01010101 00000111
(2)交換兩個值,不用臨時變數。
【例】a=3,b=4。想將a和b的值互換,可以用以下三條賦值語句實現:
a=a^b;即:a=3^4=7(0011^0100=0111)
b=b^a;即:b=4^7=3(0100^0111=0011)
a=a^b;即:a=7^3=4(0111^0011=0100)
不用temp交換兩個整數
void swap(int x , int y)
{
x ^= y;
y ^= x;
x ^= y;
}
編寫對字串進行金鑰匙異或加解密程式
有了加密程式(a^b),相應的就應該有解密程式。解密程式是加密程式的逆過程,這裡的加密和解密程式是完全相同的,原因是(a^b)^b=a。
4.“按位取反”運算子~
移位運算子:
左移、右移運算實現將一個數的各個二進位制位向左向右移若干位。
1.左移運算子<<
運算規則:對運算子<<左邊的運算量的每一位全部左移右邊運算量表示的位數,右邊空出的位補0。
【例】a<<2表示將a的各位依次向左移2位,a的最高2位移出去捨棄,空出的低2位以0填補。
例:char a=0x21;
則a<<2的過程 0010 0001〈〈2 = 1000 0100;即 a<<2的值為0x84。
左移1位相當於該數乘以2,左移n位相當於該數乘以2n。
乘法運算轉化成位運算 (在不產生溢位的情況下)
a * (2^n) 等價於 a<< n
2. 右移運算子>>
運算規則:對運算子>>左邊的運算量的每一位全部右移右邊運算量表示的位數,右邊低位被移出去捨棄掉,空出的高位補0還是補1,分兩種情況:
(1)對無符號數進行右移時,空出的高位補0。這種右移稱為邏輯右移。
(2)對帶符號數進行右移時,空出的高位全部以符號位填補。即正數補0,負數補1。這種右移稱為算術右移。
右移1位相當於除以2,同樣,右移n位相當於除以2n。
除法運算轉化成位運算 (在不產生溢位的情況下)
a / (2^n) 等價於 a>> n
取模運算轉化成位運算 (在不產生溢位的情況下)
a % (2^n) 等價於 a & (2^n - 1)
迴圈移位的實現。
如將一個無符號整數x的各位進行迴圈左移4位的運算,即把移出的高位填補在空出的低位處。
可以用以下步驟實現:
(1)將x左移4位,空出的低4位補0,可通過表示式x<<4實現。
(2)將x的左端高4位右移到右端低4位,可通過表示式x>>(16-4)實現。由於x為無符號整數,故空出的左端補0。
(3)將上述兩個表示式的值進行按位或運算,即:
y=(x<<4) | (x>>(16-4));
x 0010 1111 0010 0001
x<<4 1111 0010 0001 0000
x>>(16-4) 0000 0000 0000 0010
y 1111 0010 0001 0010
unsigned rol ( unsigned a,int n)
{ unsigned b ;
b=(a<<n) | (a>>(16-n)) ;
return(b);}
計算絕對值
int abs( int x )
{ int y ;
y = x >> 31 ;//二進位制最高位
return (x^y)-y ; //or: (x+y)^y
}