遇到很多人問一個問題,甚至這考題根本萬年不衰,
所以我決定好好來寫一寫關於位元運算的部分,
至於會想要寫一些職務上的運用,是因為,其實我每天都會花一些些的時間,
去網路上幫人解解疑難雜症,甚至有些還會直接寄信問我,
再加上一些家教的經驗,其實我發現一件事情,
語法大家都很熟,只是,問題基本上都是卡在,
" 不會用 " 的這件事情上面,
不知道什麼時候該使用,學了不知到要用在哪,
等真正專案開始的時候,只能自己摸索,
連架構上面.... 只能說很亂,所以,我決定從這篇開始,
在教學上面,多一些我自己實務上的經驗分享和使用方法,
如果,各位看官,有更好的方式,請不要吝嗇的在下方留言或寄信分享給我,
請相信,交流,永遠是讓自己更上一層樓的方式,沒有之一。
好了,廢話不多說,我們進入主題吧。
位元運算子 (Bitwise operator) ,在數位設計上面有AND , OR , NOT , XOR 與補數..等運算,而在C++中,提供這些運算的就是位元運算子,而它們在程式裡面的表達,則是 AND ( & ) , OR ( | ) , NOT ( ! ) 以及補數 ( ~ ) 。
我們先來看看下面的表 :
這個麻煩大家先記起來,不管用什麼方式,這很重要 !
至於我自己背的方式....
就是 "AND 只有1 1得1,其他為0 , OR : 0 0 得0 其他都為1"...大概是這樣,僅供參考。
讓我們來先寫點Code舉個簡單的例子吧,
題目 : 如何判斷奇數偶數
描述 :
奇數偶數,奇數偶數在二進制裡面,有一個萬年不變的規則,那就是,
[ 奇數,最右邊的那一個位元,絕對為 1 ],
[ 偶數,最右邊的那一個位元,絕對為 0 ] ,
這句話請重複跟我念三次,因為這是絕對,所以麻煩大家也記一下。
不信 ? 很簡單,打開你電腦裡面的計算機→檢視→程式設計師模式
然後自己敲看看 ( 工程師麻...要有點實驗精神 )
接下來,我們上代碼 :
這個程式的運算原理,奇數的數值若以二進位來表示,最右邊的位元一定會為1,而偶數最右邊則一定為0,所已在使用1來與輸入的值做 & (AND)運算的時候,由於1除了最右邊的位元為1之外,其他位元都會是0,與輸入數值AND運算的結果,只會留下最右邊的位元為0或為的結果,其他部分都會被0 AND運算遮蔽掉,這就是所謂的 [ 位元遮罩 ] 例如 : 00000100 。
接下來,我們來看另外一個例子
題目 : SWAP (交換)
描述 :
交換數值,這個其實非常實用也非常常用,而且在一般初級面試的時候,這玩意也可以有一些變化,例如傳值、傳址、傳參,但是,這一篇我們的教學重點是在於位元運算,所以,我們還是把專注放在這邊吧。
首先,我先寫一個標準的交換方式 ( 所謂的標準,就是書上基本上都會出現的方法 )
接下來,我們用 ^ ( XOR ) 來實做看看 :
然後,我們一行一行來看 ,
首先,我們知道
a = 10 , b = 20
第一行 a ^= b ;
可以拆開來變成
a = a^b
那10 ^ 20 =多少 ?
10 = 1010 , 20 = 10100
11110(二進位) = 30 (十進位)
也就是說,我們將a變成了30
第二行 : b ^= a ;
拆開來變成 b = b ^ a ( 30 );
b 是多少 ? b 是 20 (10100)
所以我們再拆一次,變成 b = (20)10100 ^ (30)11110
這時候,b就 = 01010 (二進位)
01010 ( 二進位 ) = 10
也就是說,我們現在的 b = 10 , a = 30
第三行 : a ^= b; ( 此時 a = 30 , b = 10 )
一樣,我們把這行拆開來,
a ^=b 等於 a = a ^ b ;
30 = 11110
10 = 01010
a = 11110 ^ 01010
所以 a= 10100
變成 10進位的話就是20
其實寫法看各人,但是如果是我的話,基本上我還是喜歡用下面的寫法,
比較清楚也比較快。
接下來,我們來談談工作實例吧,
在什麼時候我們會使用到位元運算來操作。
首先,我先分享一個我寫的define + 一個struct
typedef struct tRdpConnectionINFO
{
RDP_LOCAL_FEATURE LocalFeature ;
}RDPCONNECTIONINFO, *PRDPCONNECTIONINFO;
typedef UINT8 RDP_LOCAL_FEATURE;
#define RDP_FEATURE_AUDIO 0x01
#define RDP_FEATURE_MIRCOPHONE 0x02
#define RDP_FEATURE_USB_DEVICES 0x04
#define RDP_FEATURE_H264 0x08
#define RDP_FEATURE_ALL (RDP_FEATURE_AUDIO | RDP_FEATURE_MIRCOPHONE | RDP_FEATURE_USB_DEVICES | RDP_FEATURE_H264)
這個define是在意思是說,這個產品有沒有打開這些功能,
假如說有的話,就是最後一個全部 | 起來,
也就是說,我在判斷這個產品有沒有打開這些能力,我只需要去這樣寫
RDPCONNECTIONINFO info = { 0 };
/*
假設我們只有打開
RDP_FEATURE_AUDIO 0x01
RDP_FEATURE_H264 0x08
這兩個flag
則我們會這樣
info.LocalFeature = RDP_FEATURE_AUDIO|RDP_FEATURE_H264;
則info.LocalFeature = 0x9
然後我們將這筆資料,送上去給上層,於是上層就可以寫以下的代碼去判斷,這個產品有支援什麼東西。
*/
if (info.LocalFeature == RDP_FEATURE_ALL)
{
//這樣代表全部都開起
}
else
{
if (info.LocalFeature & RDP_FEATURE_AUDIO)
{
/*
0x9 & 0x1 = 0x1 //所以會進到這個判斷
*/
}
if (info.LocalFeature & RDP_FEATURE_MIRCOPHONE)
{
/*
0x9 & 0x2 = 0x0 //所以不會進到這個判斷
*/
}
if (info.LocalFeature & RDP_FEATURE_USB_DEVICES)
{
/*
0x9 & 0x4 = 0x0 //所以不會進到這個判斷
*/
}
if (info.LocalFeature & RDP_FEATURE_H264)
{
/*
0x9 & 0x8 = 0x8 //所以會進到這個判斷
*/
}
如此一來,我們就可以針對產品不同的能力,
去做個別的事情,其實這是一種寫法,當然我也有看過另外一種方式 :
typedef struct tRdpConnectionINFO
{
BOOL FEATURE_AUDIO ;
BOOL FEATURE_MIRCOPHONE ;
BOOL FEATURE_USB_DEVICES ;
BOOL FEATURE_H264 ;
}RDPCONNECTIONINFO, *PRDPCONNECTIONINFO;
這種方式也...................可以,
只是......功力高下....立刻判斷而已。
這是這一篇的教學和分享,
以後如果時間允許的話,我會盡可能的以這種方式來寫作看看,
一樣,如果各位看官有更好更快的方式,
請不要吝嗇的與我分享,
謝謝。
留言列表