位元欄位
有時一個值只需要少數幾個位元——一個是/否旗標只需一個,一個 0 到 7 的值只需三個。把每個都存進一個完整的 int 會浪費空間。位元欄位讓你能宣告一個剛好佔用指定位元數的 struct 成員,於是好幾個極小的值可以被打包進一個機器字組,而不是各佔一整個位元組或更多。
在 struct 裡你給一個成員一個冒號與一個位元寬度:「struct Flags { unsigned ready : 1; unsigned mode : 3; };」宣告 ready 為單一位元(握 0 或 1)、mode 為三個位元(握 0 到 7),編譯器把它們打包在一起。接著你用普通的欄位語法讀寫它們,f.ready = 1,就像任何 struct 成員,而檯面下編譯器替你做遮罩與位移。這在鏡射硬體暫存器佈局、或在每個位元都珍貴的緊湊磁碟上或線路上格式的程式碼中很常見。
為什麼重要與提醒:位元欄位以一點 CPU 工作(每次存取時隱藏的遮罩與位移)換取小得多的儲存、以及一種可讀地為個別位元命名的方式。但它們帶有真實的可攜性警告:位元被打包的順序、它們是否跨越儲存邊界、以及確切的佈局都是實作定義的,所以位元欄位結構不是一種能跨編譯器逐位元組匹配外部二進位格式的可靠方式。對於可攜的硬體或協定工作,許多程式設計師反而在一個普通整數上使用明確的位元運算子與遮罩。
struct Flags { unsigned ready : 1; /* 一個位元:0 或 1 */ unsigned mode : 3; /* 三個位元:0..7 */ }; struct Flags f = {0}; f.ready = 1; f.mode = 5; /* 編譯器在幕後做遮罩與位移 */
ready 與 mode 合起來只佔 4 個位元;你像存取一般欄位那樣存取它們,而編譯器處理位元操弄。
位元欄位的佈局——位元順序、是否跨越儲存單元、以及填充——是實作定義的,所以位元欄位結構不是匹配外部二進位或線路格式的可攜方式。要做那件事,請在普通整數上使用明確的遮罩與位移。