位欄位(bit filed)是c語言中一種儲存結構,不同於一般結構體的是它在定義成員的時候需要指定成員所佔的位數。位字段是乙個signed int或unsigned int型別變數中一組相鄰的位(c99和c11新增了bool型別的位欄位)。位欄位通過乙個結構宣告來建立,該結構宣告為每個字段提供標籤,並確定該字段的寬度。例如,下面的宣告建立了4個1位的字段:
struct prnt;
根據該宣告,prnt包含了4個1位的字段。現在,可以通過普通的結構成員運算子(.)單獨給這些字段賦值:
prnt.itals=1
; prnt.undln=0
; prnt.bldfc=1
; prnt.autfd=0
;
下面檢視一下prnt的值:
char str[33];
int* value=reinterpret_cast
(&prnt);
itoa(*value,str,2);
printf("%d %d %d %d\n", prnt.autfd,prnt.bldfc,prnt.undln,prnt.itals);
printf("sizeof(prnt) = %d\n",sizeof(prnt));
printf("十進位制: %d\n",prnt);
printf("二進位制: %032s\n",str);
輸出的結果為:
0 1 0 1
sizeof(prnt) = 4
十進位制: 10
二進位制: 0000 0000 0000 0000 0000 0000 0000 1010
可以看出,prnt的大小為4個位元組(unsigned int 或 signed int),通過prnt的結構成員可以設定和訪問某些bit位的值。
帶有位字段的結構提供了一種記錄設定的方便途徑。許多設定(如,字型的粗體或斜體)就是簡單的二進位制一。例如,開或關、真或假。如果只需要使用1位,就不需要使用整個變數。內含位字段的結構允許在乙個儲存單元中儲存多個設定。
有時,某些設定也有多個選擇,因此需要多位來表示。例如,可以使用如下**:
structprcode;
這裡建立了兩個2位的字段和乙個8位的字段,可以這樣賦值:
prcode.code1=0
; prcode.code2=3
; prcode.code3=102
;
但是要確保賦的值不超出欄位可容納的範圍(下面會說明當超出範圍時會發生什麼事情)。
再次列印出prcode的內容
int* value_prcode=reinterpret_cast
(&prcode);
itoa(*value_prcode,str,2);
printf("%d %d %d\n",prcode.code1,prcode.code2,prcode.code3);
printf("sizeof(prcode) = %d\n",sizeof(prcode));
printf("十進位制: %d\n",prcode);
printf("二進位制: %032s\n",str);
列印結果如下:
0 3 102
sizeof(prcode) = 4
十進位制:1644
二進位制:0000 0000 0000 0000 0000 0110 0110 1100
可以看出,prcode.code1對應於0-1位元位,數值為00,對應十進位制為0;
prcode.code1對應於2-3位元位,數值為11,對應十進位制為3;
prcode.code2對應於4-11位元位,數值為0110 0110,對應十進位制為102。
因此,乙個字段可以對應於多個位元位,且當使用結構字段賦值在可容納的範圍之內時,變數可以記錄正確的值。
這裡再討論一些需要注意的問題。首先是,如果宣告的總位數超過乙個unsigned int型別的大小(4 bytes)時會發生什麼事情?結果是會用到下乙個unsigned int型別的儲存位置。乙個欄位不允許跨越兩個unsigned int之間的邊界。編譯器會自動移動跨界的字段,保持unsigned int的邊界對齊。一旦發生這種情況,第1個unsigned int中會留下乙個未命名的「洞」。例如:
structprlimit;
上面定義的位欄位大小共37個bits,超過了乙個unsigned int的範圍,給prlimit的各結構成員賦值,並使用下面**列印出prlimit所儲存的內容:
prlimit.a=0xf;
prlimit.b=0;
prlimit.c=0xf;
prlimit.d=0x1ffffff;
char str_1[33];
char str_2[33];
int* value_1=reinterpret_cast
(&prlimit);
int* value_2=reinterpret_cast
(&prlimit)+1;
itoa(*value_1,str_1,2);
itoa(*value_2,str_2,2);
printf("0x%x 0x%x 0x%x 0x%x \n",prlimit.a,prlimit.b,prlimit.c ,prlimit.d);
printf("sizeof(prlimit) = %d\n",sizeof(prlimit));
printf("二進位制 0~31位: %032s\n",str_1);
printf("二進位制 32~63位: %032s\n",str_2);
輸出的結果如下:
0xf 0x0 0xf 0x1ffffff
sizeof(prlimit) = 8
二進位制 0-31位:0000 0000 0000 0000 0000 1111 0000 1111
二進位制 32-63位:0000 0001 1111 1111 1111 1111 1111 1111
從輸出的結果可以看出,首先,prlimit的大小為8個位元組;其次,編譯器強制prlimit.d欄位發生邊界對齊,即prlimit.d位於第二個unsigned int上,prlimit.c與prlimit.d之間會填充未命名的「洞」。
struct stuff;
使用下面的**輸出stuff的內容:
stuff.field1=1;
stuff.field2=1;
stuff.field3=0xf;
char str_1[33];
char str_2[33];
int *value_1=reinterpret_cast
(&stuff);
int *value_2=reinterpret_cast
(&stuff)+1;
itoa(*value_1,str_1,2);
itoa(*value_2,str_2,2);
printf("sizeof(stuff) = %d\n",sizeof(stuff));
printf("二進位制 0-31位: %032s\n",str_1);
printf("二進位制 32-63位: %032s\n",str_2);
輸出的結果為:
sizeof(stuff) = 8
二進位制 0-31位:0000 0000 0000 0000 0000 0000 0000 1001
二進位制 32-63位: 0000 0000 0000 0000 0000 0000 0000 1111
也就是說,在這裡,stuff.field1和stuff.field2之間,有乙個2位的空隙;stuff.field3被強迫與下乙個整數對齊,儲存到下乙個unsigned int中。stuff的大小為8個位元組。
最後討論乙個當賦值超出欄位可容納範圍的問題。
struct test;
int main()
輸出的結果為:
3 3 0
二進位制:0000 0000 0000 0000 0000 0000 0000 1111
上述**中,成員test.t2賦值的大小超出了容納的範圍。可以看到,t2賦值為11(二進位制是1011),結果輸出的值是3(二進位制是011),即截斷了超出的部分。同時也可以看到,超出的部分不會影響t3的值(不同平台不一樣?網上有人說會覆蓋超出的區域)。
最後需要說明的是,字段儲存在乙個int中的順序取決於機器。在有些機器上,儲存的順序是從左往右的,而在另一些機器上,是從右往左的。另外,不同的機器中兩個字段邊界的位置也有區別。由於這些原因,位欄位通常都不容易移植。儘管如此,有些情況卻要用到這種不可移植的特性。例如,以特定硬體裝置所用的形式儲存資料。
解析C語言中位字段記憶體分配的問題
c語言的位字段是個比較有意思的特性。它的目的是在乙個機器字中儲存多個物件 每個物件佔據若 it 從而節省記憶體資源,同時又避免複雜的位運算。在此不再討論位字段的具體語法,下面將研究位字段的儲存特性。先說含有多個字段 fwww.cppcns.comield 的字 word 所佔空間的規律 含有多個欄位...
C語言位欄位
位欄位是 c語言中一種儲存結構,不同於一般結構體的是它在定義成員的時候需要指定成員所佔的位數。乙個位欄位必須儲存在同乙個位元組中不能跨越兩個位元組 如果乙個位元組所剩空間不夠存放另乙個位字段時 將從下一位元組起存放此位字段 可以定義無名位字段 這時它只用來作填充或調整位置 0寬度的無名位字段用來使下...
位欄位 C語言
位字段是乙個signed int 或 unsigned innt中的一組相鄰的位,位字段由乙個結構宣告建立,該結構為每個字段提供標籤,並決定欄位的寬度。例如,以下建立4個1位欄位 struct print 也可以宣告多位如 struct print 這裡需要注意乙個問題 如果宣告的總位數超過乙個un...