C語言中文網 目錄

C語言位字段

位字段(bit-field)是一個由具有特定數量的位組成的整數變量。結構或聯合的成員也可以是位字段。如果連續聲明多個小的位字段,編譯器會將它們合并成一個機器字(word)。這使得小單元信息具有更加緊湊的存儲方式。當然,也可以使用位運算符來獨立處理特定位,但是位字段允許我們利用名稱來處理位,類似于結構或聯合的成員。

位字段的聲明格式為:

類型[成員名稱]:寬度;


各部分的詳細描述如下:

(1) 類型
指定一個整數類型,用來決定該位字段值被解釋的方式。類型可以是 _Bool、int、signed int、unsigned int,或者為所選實現版本所提供的類型。這里的類型也可以包含類型限定符。

具有 signed int 類型的位字段會被解釋成有符號數;具有 unsigned int 類型的位字段會被解釋成無符號數。具有 int 類型的位字段可以是有符號或無符號的類型,由編譯器決定。

(2) 成員名稱
成員名稱是可選的(可以不寫)。但是,如果聲明了一個無名稱的位字段,就沒有辦法獲取它。沒有名稱的位字段只能用于填充(padding),以幫助后續的位字段在機器字中對齊到特定的地址邊界。

(3) 寬度
位字段中位的數量。寬度必須是一個常量整數表達式,其值是非負的,并且必須小于或等于指定類型的位寬。無名稱位字段的寬度可以是 0。在這種情況下,下一個聲明的位字段就會從新的可尋址內存單元開始。

當在一個結構或聯合內聲明一個位字段的時候,編譯器會分配一個足以容納它的可尋址內存單元。通常情況下,被分配的內存單元是一個 int 類型的機器字。

如果緊接著的位字段適合同一內存單元中剩下的空間,那么就被定義到與前面的位字段緊鄰的位置。如果不適合的話,那么編譯器就分配另外的內存單元,并在新單元的起始放置下一個位字段,或者跨過前一個內存單元的結尾和下一個內存單元的開頭。

下面的例子重新定義了結構類型 struct Date,讓其成員 month 和 day 只占據各自需要的位數。為了展示 _Bool 類型的位字段,我們為夏令時設定一個標簽。這段代碼以目標機器使用至少 32 位字為前提:
struct Date {
unsigned int month : 4;         // 1是1月;12是12月
unsigned int day   : 5;         // 月份中的日(1~31)
signed int   year  : 22;        // (-2097152~+2097151)
_Bool        isDST : 1;     // 如果是夏令時,則為true
};

n 位的位字段可以有 2n 個不同的值。結構成員 month 的取值范圍是 0~15;成員 day 的取值范圍是 0~31;成員 year 的值范圍是 -2097152~+2097151。我們可以使用常見的初始化列表方式初始化一個 struct Date 類型的對象:
struct Date birthday = { 5, 17, 1982 };

對象 birthday 占據的存儲空間大小與一個 32 位的 int 整數對象一樣。和結構中其他成員所不同的是,位字段通常不會占據可尋址的內存位置,因此無法對位字段采用地址運算符(&)或宏 offsetof。

但是在其他方面,可以將位字段看作結構或聯合成員,使用點和箭頭運算符來獲取,并以類似對待 int 或 unsigned int 變量的方式對其進行算術運算。因此,使用位字段重新定義的 Date 結構在函數 dateAsString()中不需作任何修改:
const char *dateAsString( struct Date d )
{
  static char strDate[12];
  sprintf( strDate, "%02d/%02d/%04d", d.month, d.day, d.year );
  return strDate;
}

下面的語句為對象 birthday 調用函數 dateAsString(),并采用標準函數 puts()輸出結果:
puts( dateAsString( birthday ));

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo