close

 

 

遇到很多人問一個問題,甚至這考題根本萬年不衰,

所以我決定好好來寫一寫關於位元運算的部分,

至於會想要寫一些職務上的運用,是因為,其實我每天都會花一些些的時間,

去網路上幫人解解疑難雜症,甚至有些還會直接寄信問我,

再加上一些家教的經驗,其實我發現一件事情,

語法大家都很熟,只是,問題基本上都是卡在,

" 不會用 " 的這件事情上面,

不知道什麼時候該使用,學了不知到要用在哪,

等真正專案開始的時候,只能自己摸索,

連架構上面....  只能說很亂,所以,我決定從這篇開始,

在教學上面,多一些我自己實務上的經驗分享和使用方法,

如果,各位看官,有更好的方式,請不要吝嗇的在下方留言或寄信分享給我,

請相信,交流,永遠是讓自己更上一層樓的方式,沒有之一。

好了,廢話不多說,我們進入主題吧。

 

 

 

位元運算子 (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;

 

這種方式也...................可以,

只是......功力高下....立刻判斷而已。

 

 

這是這一篇的教學和分享,

以後如果時間允許的話,我會盡可能的以這種方式來寫作看看,

一樣,如果各位看官有更好更快的方式,

請不要吝嗇的與我分享,

謝謝。

 

 

 

 

 

arrow
arrow
    全站熱搜

    Eric 發表在 痞客邦 留言(2) 人氣()