資訊處理中,有些資訊在儲存時,並不需要佔用一個完整的位元組,而只需佔一個或幾個位元位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位制位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。
所謂“位域”是把一個位元組中的位元位劃分為幾個不同的區域, 並說明每個區域的位數。每個域有一個域名,允許在程式中按域名進行操作。 這樣就可以把幾個不同的物件用一個位元組的二進位制位域來表示。位域在本質上就是一種結構型別, 不過其成員是按二進位制位分配的。
1.位域的定義
位域是透過結構體來定義的,相比較普通的結構體,位域的成員需要明確標註其所佔位元位的長度。
位域定義的基本語法如下:
struct 位域結構體名
{
位域列表
};
其中位域列表 “型別說明符 位域名 : 位域長度;”
2.位域變數的定義
位域變數的說明與結構變數說明的方式相同。 可採用先定義後說明、同時定義說明、直接說明這三種方式。
例如:
struct BitField
{
char a:8;
char b:2;
char c:5;
}weiyu;
weiyu為BitField變數,共佔兩個位元組。
3.位域的注意事項
1)一個位域必須儲存在同一個儲存單元中,不能跨兩個儲存單元。
2)一個儲存單元所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bf
{
unsigned char a:4;
unsigned char :0; /*空域*/
unsigned char b:4; /*從下一單元開始存放*/
unsigned char c:4;
};
在這個位域定義中,a佔第一位元組的4位,後4位填0表示不使用,b從第二位元組開始,佔用4位,c佔用4位。
3) 位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
struct k
{
int a:1;
int :2; /*該2位不能使用*/
int b:3;
int c:2;
};
4)位域列表中,儘可能不要出現不同型別的域,否則,不同的編譯器下得到的位域的長度將不一致。
4.位域的使用
位域的使用和結構成員的使用相同,其一般形式為: 位域變數名·位域名
5.位域在記憶體中儲存模式
不同的晶片儲存次序是不同的,對於Intel晶片,是按照從低位開始儲存的,而對於Motolola晶片則正好相反。因此在使用不同晶片之間進行資料傳輸使用位域儲存的資料的時候,必須知道是否是相同的晶片之間的資料傳輸,因為在資訊的接收端要確保按照正確的次序讀取相應的位域,否則將會發生不可預知的錯誤!!!
三、位域示例
Demo1:對某位域分別賦值,之後對位域進行不同的賦值或者位運算,並分別向螢幕輸出位域。
#include"stdio.h"
struct bf
{
unsigned char a:1;
unsigned char b:3;
unsigned char c:3;
};
int main()
{
bf bit, *pbit;
bit.a = 1;
bit.b = 7;
bit.c = 2;
printf(" %d,%d,%d\n",bit.a,bit.b,bit.c);
pbit = &bit;
pbit->a = 0;
pbit->b &= 0x5;
pbit->c |= 0x5;
printf(" %d,%d,%d\n",pbit->a,pbit->b,pbit->c);
printf( " length of bitfield : %d", sizeof( bf ) );
return 0;
}
Demo2:對位域整體進行賦值,之後分別輸出每個位域
#include"stdio.h"
struct BF
{
unsigned char a:5;
unsigned char b:2;
unsigned char c:4;
};
int main()
{
BF *val;
unsigned short aa = 1000;//1111101000
val = ( struct BF * )&aa;
printf(" BF.a = %d\n", val->a);
printf(" BF.b = %d\n", val->b);
printf(" BF.c = %d\n", val->c);
return 0;
}
記憶體狀態
可以看出,位域其實就是一種結構型別, 只不過成員佔用空間大小是按Bit分配的。