用 C 語言處理常見的旗標位元運算
正如國中理化課所說,電子產品都是由滿滿『0、1』所構成,大家早就都了解這件事。但現實上,由於要求的功能愈疊愈多,低階的運算早就被眾人所忽略。無論大家如何忙著處理物件的繼承問題,又或者是因時間太多而研究『1+1=2 慢吞吞語言』,低階的運算還是依然沒有消失,反而更為重要。
位元運算不外乎就是『AND、OR、XOR...』等邏輯概念,主要目的是把『1 變 0』、『0 變 1』或有條件維持不變,在程式中比較常看到的地方,通常會在硬體驅動程式(Driver)之中。而在高階應用程式中,也往往因為要旗標條件的判斷,也會看得到其存在,如 Linux 下的檔案權限。
一個更貼切的例子,假設我們現在寫一個滑鼠驅動程式,我們要怎麼設計資料結構,讓應用程式得知用戶(User)按了哪幾個鍵?用戶可能是一次只按『一個鍵』,也可能一次按『左右兩個鍵』,更有可能按『左鍵和中間鍵』,有多種組合存在。
一般初學程式者可能會用 boolean 或 int 這樣寫:
但明明只是『0、1』,為何要用到 int 資料形態?除了浪費記憶體,運算上也整整慢了好幾個 CPU Clock。所以,多數程式開發者碰到此類問題,會比較偏好以位元為最小單位來寫:
當設定哪幾個鍵被按下,只要用位元運算設定旗標就可以了:
當然,反向設定也是可以:
後記
以前小時候不懂事,又被很多高階 API 保護得很好,常被驅動程式中的位元運算嚇哭,其實,雖然位元運算看起來可以千變萬化,但就那幾種用法最常用而已。在此筆記之,讓大家一起哭。
位元運算不外乎就是『AND、OR、XOR...』等邏輯概念,主要目的是把『1 變 0』、『0 變 1』或有條件維持不變,在程式中比較常看到的地方,通常會在硬體驅動程式(Driver)之中。而在高階應用程式中,也往往因為要旗標條件的判斷,也會看得到其存在,如 Linux 下的檔案權限。
一個更貼切的例子,假設我們現在寫一個滑鼠驅動程式,我們要怎麼設計資料結構,讓應用程式得知用戶(User)按了哪幾個鍵?用戶可能是一次只按『一個鍵』,也可能一次按『左右兩個鍵』,更有可能按『左鍵和中間鍵』,有多種組合存在。
一般初學程式者可能會用 boolean 或 int 這樣寫:
struct _mouse_event { int button1; int button2; int button3; ... };
但明明只是『0、1』,為何要用到 int 資料形態?除了浪費記憶體,運算上也整整慢了好幾個 CPU Clock。所以,多數程式開發者碰到此類問題,會比較偏好以位元為最小單位來寫:
enum { MOUSE_LEFT_BUTTON = (1 << 0), MOUSE_MIDDLE_BUTTON = (1 << 1), MOUSE_RIGHT_BUTTON = (1 << 2) }; struct _mouse_event { int button; ... };
當設定哪幾個鍵被按下,只要用位元運算設定旗標就可以了:
struct _mouse_event mouse; mouse.button |= MOUSE_LEFT_BUTTON; mouse.button |= MOUSE_LEFT_BUTTON | MOUSE_RIGHT_BUTTON;
當然,反向設定也是可以:
mouse.button &= ~(MOUSE_MIDDLE_BUTTON); mouse.button &= ~(MOUSE_MIDDLE_BUTTON | MOUSE_RIGHT_BUTTON);
後記
以前小時候不懂事,又被很多高階 API 保護得很好,常被驅動程式中的位元運算嚇哭,其實,雖然位元運算看起來可以千變萬化,但就那幾種用法最常用而已。在此筆記之,讓大家一起哭。
如果把program的工作機,統統換成十年前的等級,這樣「訓練」出來應該就不容易被嚇哭了。 XD
回覆刪除我已經被嚇的不止十年了, 至今仍會發抖呀!!!
回覆刪除看來要換成二十年前的了...
讓大家一起哭。 XD
回覆刪除有沒有再進階的運算呀
回覆刪除