位域的概念
1個字節包含8位,有些變量保存的數據不需要占用這么長的空間(比如bool類型,只有兩個狀態true和false, 1位就可以搞定,剩下的7位就浪費了),這就催生了“位域”結構,位域將1個字節划分成不同的區域,每個區域都有個位域名,程序員可以代碼通過位域名訪問其中的數據。
位域的聲明
類型 位域名:位域長度;
位域結構體,我理解是一種特殊的結構體,其成員變量都是位域,聲明如下
struct 位域結構名 { 類型說明符 位域名:位域長度; ... 類型說明符 位域名:位域長度; };
基本原則
現有一個簡單的結構體
typedef struct Test1 { char a:1; int b:2; }test1;
1. 位域變量的長度不能大於其類型的長度(sizeof(類型) * 8)
變量char has_assoc的類型位char 1字節 8位,小於定義的10,所以編譯器警告
2. 不能用於位域字段的操作:取地址操作符&,取偏移量操作
位域是若干位空間,是沒有地址的
3. 位域可以是無名位域,無名位域只能用作填充或調整位置,不能使用。
typedef struct Test1 { char a:1; int b:2; int :1; }test1;
4. 位域字段不能聲明為類的靜態成員
5. 位域結構體的大小必須是其最長基本類型大小的整數倍(sizeof(類型) * 8)
6.如果一個字節所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bs { unsigned a:4 unsigned :0 /*空域*/ unsigned b:4 /*從下一單元開始存放*/ unsigned c:4 }
這個位域定義中,a占第一字節的4位,后4位填0表示不使用,b從第二字節開始,占用4位,c占用4位。
7.不夠一個類型的size時,將按其中最大的那個類型對齊。
struct foo4 { char a : 2; char b : 3; int c : 1; };
foo4中雖然三個位域所占用空間之和為6 bit < 8 bit(1 byte),但是由於char和int的對齊系數是不同的,是不能捆綁在一起,那是不是a、b捆綁在一起按照char對齊,c單獨按照int對齊呢?我們 打印一下sizeof(struct foo4)發現結果為8,也就是說編譯器把a、b、c一起捆綁起來並以int做對齊了。
8.如果位域字段之間穿插着非位域字段,則不進行壓縮;
typedef struct Test1 { char a:1; int b:2; }test1; //運行結果:4 typedef struct Test1 { char a:1; int b:2; long c; }test1; //運行結果:16
總結:
1) 如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止
2) 如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數倍;
3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6采取不壓縮方式,GCC采取壓縮方式;
4) 如果位域字段之間穿插着非位域字段,則不進行壓縮;
5) 整個結構體的總大小為最寬基本類型成員大小的整數倍。


