C語言學習筆記11--位運算
位運算概念
位運算是指按二進位制位進行的運算。因為在系統軟體中,常要處理二進位制位的問題。
例如:將一個儲存單元中的各二進位制位左移或右移一位,兩個數按位相加等。
c語言提供位運算的功能,與其他高階語言(如PASCAL)相比,具有很大的優越性。
位運算子和位運算
位運算子和位運算
(1)位運算子中除~以外,均為二目(元)運算子,即要求兩側各有一個運算量。
(2)運算量只能是整型或字元型的資料,不能為實型資料(浮點型)
“按位與”運算子(&)
含義:參加運算的兩個資料,按二進位制位進行“與”運算。
如果兩個相應的二進位制位都為1,則該位的結果值為1;否則為0。
例如:
0&0 = 0,0&1 = 0,
1&0 = 0,1&1 = 1
注意:
3&5並不等於8, 應該是按位與運算:
位運算子和位運算
如果參加&運算的是負數(如-3&-5), 則要
以補碼形式表示為二進位制數,然後再按位進行“與”運算。
按位與運算的用途
一、 清零
若想對一個儲存單元清零,即使其全部二進位制位為0,只要找一個二進位制數,其中各個位符合以下條件:原來的數中為1的位,新數中相應位為0。然後使二者進行&運算,即可達到清零目的。
例如:要求將二進位制數11100101的第2位清零
1 1 1 0 0 1 0 1
& 1 1 1 1 1 0 1 1
————————————
1 1 1 0 0 0 0 1
二、取一個數中某些指定位
例如:我們需要對一個字型資料取出其低8位的值時,我們可以這麼做。
“按位或”運算子(|)
兩個相應的二進位制位中只要有一個為1,該位的結果值為1。
即:
0|0=0,0|1=1,
1|0=1,1|1=1
例如:
例:大小寫轉化
#include <stdio.h>
#include <conio.h>
void main()
{
char ch, temp;
printf("請輸入一個字母: \n");
ch = getchar();
temp = getchar();
while( !(ch>'A' && ch<'z') || (ch > 'Z' && ch < 'a') )
{
printf("輸入有誤, 請重新輸入一個字母: \n");
ch = getchar();
}
if( ch & 32 )
{
ch = ch & 223; // 使第五位為0,變大寫
}
else
{
ch = ch | 255; // 使第五位為1,變小寫
}
putchar(ch);
printf("\n");
}
因為回車了一下,回車也是一個字元,所以用getchar從輸入流中接收了回車符。所以用temp = getchar();這句接收下一。要不就出現兩句
這裡有專門的清除快取的函式。可以百度一下。
“異或”運算子(^)
異或運算子^也稱XOR運算子。
它的規則是:
若參加運算的兩個二進位制位同號則結果為0
(假),異號則結果為1(真)
即: 0^0=0,0^1=1,1^0=1, 1^1=0
例如:
異或運算子
^運算子應用
一、使特定位翻轉
設有01111010,想使其低4位翻轉,即1變為0,0變為1。可以將它與00001111進行^運算,即:
異或運算子使指定為翻轉
二、與0相^,保留原值
例如:
異或運算子的應用
因為原數中的1與0進行^運算得1,0^0得0,故保留原數。
三、交換兩個值,不用臨時變數
!這玩意新鮮!
例如:a=3,b=4,現在想將a、b變數的值交換位置,我們傳統的做法是定義多一個temp變數,而現在temp去度蜜月了,怎麼辦?
我們可以這樣做:
a=a^b;
b=b^a;
a=a^b;
這種方法也常應用於加密演算法。
XOR異或
“取反”運算子(~)
~是一個單目(元)運算子,用來對一個二進位制數按位取反,即將0變1,將1變0。
例如,~025是對八進位制數25(即二進位制數00010101)按位求反。
例如:
“取反”運算子
左移運算子(<<)
左移運算子是用來將一個數的各二進位制 位全部左移若干位。
例如:a =<< 2 將a的二進位制數左移2位,右邊補0。
若a=15,即二進位制數00001111,左移2位得00111100,(十進位制數60)
若高位左移後溢位,捨棄。
左移1位相當於該數乘以2,左移2位相當於該數乘以4,15<<2=60,即乘了4。
但此結論只適用於該數左移時被溢位捨棄的高位中不包含1的情況。
假設以一個位元組(8位)存一個整數,若a為無符號整型變數,則a=64時,左移一位時溢位的是0,而左移2位時,溢位的高位中包含1。
右移運算子(>>)
右移運算子是a>>2表示將a的各二進位制位右移2位,移到右端的低位被捨棄,對無符號數,高位補0。
例如:a=017時: a的值用二進位制形式表示為00001111, 捨棄低2位11,得到 a >> 2 == 00000011
右移一位相當於除以2
右移n位相當於除以2^n
在右移時,需要注意符號位問題:
對無符號數,右移時左邊高位移入0;
對於有符號的值,如果原來符號位為0(該數為正),則左邊也是移入0。
如果符號位原來為1(即負數), 則左邊移入0還是1,要取決於所用的計算機系統。有的系統移入0,有的系統移入1。
移入0的稱為“邏輯右移”, 即簡單右移;移入1的稱為“算術右移”。
例:a的值是十進位制數 -2:
a == 1111 1110(用二進位制形式表示)
無符號數:a>>1: 0111 1111 (邏輯右移時)
有符號數:a>>1: 1111 1111 (算術右移時)
位運算賦值運算子
位運算子與賦值運算子可以組成複合賦值運算子。
例如: &=, |=, >>=, <<=, ∧=
∴
a & = b 相當於 a = a & b
a << =2 相當於 a = a << 2
位運算舉例
題目:取一個char a從右端開始的2~5位。
① 先使a右移2位:a >> 2
目的是使要取出的那幾位移到最右端,圖示:
② 設定一個低4位全為1,其餘全為0的數。
~ ( ~ 0 << 4 )
③ 將上面①、②進行&運算。
(a >> 4) & ~ ( ~ 0 << 4 )
題目:要求將a進行右迴圈移位
迴圈移位
位段
資訊的存取一般以位元組為單位。實際上,有時儲存一個資訊不必用一個或多個位元組。
例如,“真”或“假”用0或1表示,只需1位即可。
在計算機用於過程控制、引數檢測或資料通訊領域時,控制資訊往往只佔一個位元組中的一個或幾個二進位制位,常常在一個位元組中放幾個資訊。
C語言允許在一個結構體中以位為單位來指定其成員所佔記憶體長度,這種以位為單位的成員稱為“位段”或稱“位域” ( bit field) 。利用位段能夠用較少的位數儲存資料。
如
struct packed-data
{ unsigned a:2;
unsigned b:6;
unsigned c:4;
unsigned d:4;
int i;
}data;
關於位段的定義和引用的說明
(1) 位段成員的型別必須指定為unsigned或int型別。
(2) 若某一位段要從另一個字開始存放,可用以下形式定義:
unsigned a:1;
unsignedb:2;一個儲存單元
unsigned:0;
unsigned c:3;另一儲存單元
a、b、c應連續存放在一個儲存單元中,由於用了長度為0的位段,其作用是使下一個位段從下一個儲存單元開始存放。因此,只將a、b儲存在一個儲存單元中,c另存在下一個單元(“儲存單元”可能是一個位元組,也可能是2個位元組,視不同的編譯系統而異)。
(3) 一個位段必須儲存在同一儲存單元中,不能跨兩個單元。如果第一個單元空間不能容納下一個位段,則該空間不用,而從下一個單元起存放該位段。
(4) 可以定義無名位段。
(5) 位段的長度不能大於儲存單元的長度,也不能定義位段陣列。
(6) 位段可以用整型格式符輸出。
(7) 位段可以在數值表示式中引用,它會被系統自動地轉換成整型數。