在 C 語言中,如果我們要對特定的 bit(s) 做操作的話,最直覺的方式是用 bit and(&
)跟 bit or(|
):
int bit_sample = 0x0123; /* 0000 0001 0010 0011 */ |
從上面的例子可以看到如何使用 bit and/or 來操作特定的 bit,這種方式對於單一個 bit 並不會太麻煩,但有以下缺點:
- 無法覆用:這種方式不能快速地建立一個方法,也比較不好理解
- 對於區間上就不好使了
如果要解決上述缺點,有一個方式是使用 union
,一個在嵌入式、驅動程式裡常常用到的方法。
Union#
union
是 C 語言裡面可以對一個結構裡面的元素,可以有不同的資料型態去理解,如以下例子:
union sample { |
需要注意的是:同一時間內只能存取一個屬性,準確來說他們是共用一個記憶體區塊,所以改第一個值第二個值會同時更改。[1]
struct#
奇怪,不是在講 union
嗎,怎麼會提到 struct
呢?那是因為 C 裡面有一個有趣的東西叫做位元欄位[2],這個東西必須搭配結構使用;先看例子:
struct bit_row { |
乍看之下好像跟一般的結構差不多,可是我們注意到在每個元素宣告的結尾多了一個 : 數字
,這是什麼意思?
- 首先,
unsigned short
在 64 位元裡大小是 4位,unsigned int
則是 8位 - 加上
: 數字
,這個東西就叫位元欄位,我們可以限制當前元素的大小 - 因此,元素 1 的大小就被我們縮至 1 位,依此類推
有了上述的工具就可以建立一個好用而且好理解的位元操作方法!
union method_ex { |
建立好上面這個 union 後,如果要將某一個整數的第 3 到 4 位 的值改掉,可以這樣寫
union method_ex int_ex; |
這樣的寫法,更簡單,更易懂。
剩下的空間#
值得注意的一件事,我們沿用上面的例子;method_ex
有一個元素叫真正的值,他是一個整數(8 位),剛好另外一個元素我們使用位元欄位的技巧也控制在 8 位;但,如果我們沒有這麼做呢?
答案是:你可以這麼寫,不會有什麼問題,但不建議。
更大#
如果 bits
結構今天大於 8 位,那我們就沒辦法透過更改真正的值來改變到高於 8 位的值,因此這麼做是沒意義的。
更小#
如果 bits
結構今天小於 8 位,這麼做完全不會有任何問題,但習慣上,我們會把它補齊,像是我們在 attribute 篇裡提到的 padding。
union method_ex { |
沒有定義第 7 位
union method_ex { |
隨便取名,只要有定義就好