C 迷你系列(四) 位域

位域

位段(或稱“位域”丽蝎,Bit field)為一種 數(shù)據(jù)結(jié)構(gòu),可以把數(shù)據(jù)以 位元 的形式緊湊的儲存擎鸠,并允許程序員對此結(jié)構(gòu)的位元進(jìn)行操作揭鳞。

好處

  • 可以使數(shù)據(jù)單元節(jié)省儲存空間炕贵,當(dāng)程序需要成千上萬個數(shù)據(jù)單元時,這種方法就顯得尤為重要汹桦。
  • 段可以很方便的訪問一個 整數(shù) 值的部分內(nèi)容從而可以簡化程序源代碼鲁驶。

缺點(diǎn)

而位域這種數(shù)據(jù)結(jié)構(gòu)的缺點(diǎn)在于,其內(nèi)存分配與內(nèi)存對齊的實(shí)現(xiàn)方式依賴于具體的機(jī)器和系統(tǒng)舞骆,在不同的平臺可能有不同的結(jié)果钥弯,這導(dǎo)致了位段在本質(zhì)上是不可移植的。

C 中的位域

有些信息在存儲時督禽,并不需要占用一個完整的字節(jié)脆霎, 而只需占幾個或一個二進(jìn)制位。例如在存放一個開關(guān)量時狈惫,只有 0 和 1 兩種狀態(tài)睛蛛, 用一位二進(jìn)位即可鹦马。為了節(jié)省存儲空間,并使處理簡便忆肾,C 又提供了一種數(shù)據(jù)結(jié)構(gòu)荸频,稱為“位域”或“位段”。所謂“位域”是把一個字節(jié)中的二進(jìn)位劃分為幾個不同的區(qū)域客冈, 并說明每個區(qū)域的位數(shù)旭从。每個域有一個域名,允許在程序中按域名進(jìn)行操作场仲。 這樣就可以把幾個不同的對象用一個字節(jié)的二進(jìn)制位域來表示和悦。在聲明時,位段成員必須是整形或枚舉類型(通常是無符號類型)渠缕,且在成員名的后面是一個冒號和一個整數(shù)鸽素,整數(shù)規(guī)定了成員所占用的位元數(shù)。位域不能是靜態(tài)類型亦鳞。不能使用 & 對位域做取地址運(yùn)算馍忽,因此不存在位域的指針,編譯器通常不支持位域的引用(reference)蚜迅。以下程序則展示了一個位域的聲明:

例 1

struct p_t
{
    int a:5;
    int b:2;
    int c:9;
} p;

對于變量 p 來說舵匾,p 有三個成員:a、b谁不、c,其中:a 占 5 位徽诲,b 占用 2 位刹帕,c 占用 9 位。那么 p 占用 16 位谎替,即 2 字節(jié)偷溺!錯~,總共占用 4 字節(jié)钱贯。不信挫掏?

struct p_t
{
    int a:5;
    int b:2;
    int c:4;
} p;

int main()
{
    printf("size of p is %lu\n", sizeof p);
    return 0;
}
--- output
size of p is 4

不是說是按位存儲嗎?怎么會是 4 字節(jié)呢秩命?


image.png

從圖中我們可以看出尉共,a、b弃锐、c 共用了一個 int 的內(nèi)存空間袄友,一個 int 是 4 個字節(jié),所以不管你用沒用完霹菊,都至少是一個 int 內(nèi)存剧蚣。

例 2

struct p_t
{
    unsigned char a:4;
    unsigned char b:4;
} p;

int main()
{
    printf("size of p is %lu\n", sizeof p);
    return 0;
}
-- output
size of p is 1

兩個 char 占用 2 字節(jié),a 占用 4 位,b 占用 4 位鸠按,所以總共占用 1 字節(jié)礼搁。


image.png

例 3

struct p_t
{
    unsigned char a:9;
    unsigned char b:4;
} p;

有人可能會想到這樣聲明,但是該聲明不會通過編譯目尖,報錯 Width of bit-field 'a' (9 bits) exceeds width of its type (8 bits)馒吴,因?yàn)?char 本身占用 1 字節(jié) 8 位,而聲明位域 9 位卑雁,明顯超過了 char 的空間募书,所以會報錯。
Tips

位域所占位數(shù)不能超過對應(yīng)的類型字節(jié)空間测蹲,比如:char 類型莹捡,位域不能超過 8 位;int 類型扣甲,位域不能超過 32 位篮赢。

例 4

struct p_t
{
    unsigned char a:4;
    unsigned char b:5;
} p;
--- output
size of p is 2

a 和 b 是相同類型的變量,但是 a琉挖、b 總的位數(shù)已經(jīng)超過 1 字節(jié)启泣,那么 b 就會存放到新的字節(jié)空間中,如圖:

image.png

例 5

struct p_t
{
    unsigned char  a:4;
    unsigned short b:4;
} p;
--- output
size of p is 2

由于 a示辈、b 類型不同寥茫,在我的編輯器上,將 a 存儲到空間比較大的 b 上矾麻,共用 short 空間纱耻,也就是 2 字節(jié)。如果我們讓 b 是 13 位险耀,看看會發(fā)生什么弄喘?

struct p_t
{
    unsigned char  a:4;
    unsigned short b:13;
} p;
--- output
size of p is 4

我們發(fā)現(xiàn)總共占用 4 字節(jié),為什么是 4 字節(jié)呢甩牺?a蘑志、b 總共 17 位,占用三個字節(jié)贬派,由于存在內(nèi)存對齊急但,需要額外的補(bǔ) 1 字節(jié)作為對齊(關(guān)于內(nèi)存對齊的知識參考前一篇文章)。

例 6

struct p_t
{
    unsigned char a: 2;
    unsigned char   : 2;
    unsigned char b: 4;
} p;
--- output
size of p is 1

在 a 與 b 之間有個無名的位域赠群,位數(shù)為 2羊始,那么意思就是說這兩位留空,b 存儲在這兩位之后查描,如圖:


image.png

例 7

struct p_t
{
    unsigned char a: 2;
    unsigned char   : 0;
    unsigned char b: 4;
} p;
--- output
size of p is 2

這次無名位域的值位 0突委,我們發(fā)現(xiàn)總的內(nèi)存占用變成了 2 字節(jié)柏卤,也就是說如過無名位域是 0 的話,那么會強(qiáng)制后續(xù)的位域在新的空間中分配匀油。注意:只有無名位域才可能為 0缘缚。

例 8

struct p_t
{
    unsigned char a: 2;
    unsigned char b;
    unsigned char c: 4;
} p;
--- output
size of p is 3

如果中間穿插非位域成員,會強(qiáng)制后續(xù)字段在新的空間分配(前提是位域類型相同敌蚜,如果說不同的類型桥滨,不同的編譯器會有不同的優(yōu)化方式)。


參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弛车,一起剝皮案震驚了整個濱河市齐媒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纷跛,老刑警劉巖喻括,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贫奠,居然都是意外死亡唬血,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門唤崭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拷恨,“玉大人,你說我怎么就攤上這事谢肾⊥笾叮” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵芦疏,是天一觀的道長兜挨。 經(jīng)常有香客問我,道長眯分,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任柒桑,我火速辦了婚禮弊决,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘魁淳。我一直安慰自己飘诗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布界逛。 她就那樣靜靜地躺著昆稿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪息拜。 梳的紋絲不亂的頭發(fā)上溉潭,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天净响,我揣著相機(jī)與錄音,去河邊找鬼喳瓣。 笑死馋贤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的畏陕。 我是一名探鬼主播配乓,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼惠毁!你這毒婦竟也來了犹芹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤鞠绰,失蹤者是張志新(化名)和其女友劉穎腰埂,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洞豁,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盐固,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丈挟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刁卜。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖曙咽,靈堂內(nèi)的尸體忽然破棺而出蛔趴,到底是詐尸還是另有隱情,我是刑警寧澤例朱,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布孝情,位于F島的核電站,受9級特大地震影響洒嗤,放射性物質(zhì)發(fā)生泄漏箫荡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一渔隶、第九天 我趴在偏房一處隱蔽的房頂上張望羔挡。 院中可真熱鬧,春花似錦间唉、人聲如沸绞灼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽低矮。三九已至,卻和暖如春被冒,著一層夾襖步出監(jiān)牢的瞬間军掂,已是汗流浹背轮蜕。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留良姆,地道東北人肠虽。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像玛追,于是被迫代替她去往敵國和親税课。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360