C語言:位域
這是很基礎的教程,我只是寫給自己看,作為一個學習筆記記錄一下,如果正在閱讀的你覺得簡單,請不要批評,可以關掉選擇離開
如何學好一門程式語言
- 掌握基礎知識,為將來進一步學習打下良好的基礎。
- 上機實踐,通過大量的例題學習怎麼設計演算法,培養解題思路。
- 養成良好的編碼習慣,註釋一定要寫,要不然保你一週後自己寫的程式碼都不認識了
如果我們需要定義一個結構體,結構體中的成員只有 True\False (0 or 1)兩個狀態。一般情況下我們的結構體會定義為:
struct { unsigned int widthValidated; unsigned int heightValidated; } status;
但是上面的結構體會佔用8 byte的儲存空間,我們實際上並不需要這麼多,因為成員要麼是0,要麼是1,只需要1 bit的儲存空間,因此我們可以定義變數的寬度來告訴編譯器,我們使用多少位元組:
struct { unsigned int widthValidated : 1; unsigned int heightValidated : 1; } status;
現在,上面的結構中,status 變數將佔用 4 個byte的記憶體空間,但是隻有 2 bit被用來儲存值。如果您用了 32 個變數,每一個變數寬度為 1 位,那麼 status 結構將使用 4 個位元組,但只要您再多用一個變數,如果使用了 33 個變數,那麼它將分配記憶體的下一段來儲存第 33 個變數,這個時候就開始使用 8 個位元組。讓我們看看下面的例項來理解這個概念:
#include <stdio.h> #include <string.h> /* 定義簡單的結構 */ struct{ unsigned int widthValidated; unsigned int heightValidated; } status1; /* 定義位域結構 */ struct{ unsigned int widthValidated : 1; unsigned int heightValidated : 1; } status2; int main(){ printf("佔用的記憶體大小: %d\n", sizeof(status1)); // 4 printf("佔用的記憶體大小: %d\n", sizeof(status2)); // 8 return 0; }
位域宣告
有些資訊在儲存時,並不需要佔用一個完整的位元組,而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有 0 和 1 兩種狀態,用 1 位二進位即可。
為了節省儲存空間,並使處理簡便,C 語言提供了一種資料結構,稱為"位域"或"位段",帶有預定義寬度的變數,位域定義與結構定義相仿,其形式為:
struct 位域結構名 { type [member_name] : width ; ... };
其中
- type:只能為 int,unsigned int,signed int
- member_name:位域的名稱。
- width:位域中位的數量。寬度必須小於或等於指定型別的位寬度。
例如,需要一個變數來儲存從 0 到 7 的值,您可以定義一個寬度為 3 位的位域,如下:
age 變數將只使用 3 位來儲存這個值,
struct AGE { unsigned int age : 3; } Age;
data 為 bs 變數,使用了兩個位元組,其中位域 a 佔 8 位,位域 b 佔 2 位,位域 c 佔 6 位。
struct bs{ int a:8; int b:2; int c:6; }data;
超出位域則無法完成
#include <stdio.h> #include <string.h> struct{ unsigned int age : 3; } Age; int main(){ Age.age = 4; printf("Sizeof( Age ) : %d\n", sizeof(Age)); // 4 printf("Age.age : %d\n", Age.age); // 4 Age.age = 7; printf("Age.age : %d\n", Age.age); // 7 Age.age = 8; // 二進位制表示為 1000 有四位,超出 printf("Age.age : %d\n", Age.age); // 0 return 0; }超出位域會異常
對於位域的定義尚有以下幾點說明:
一個位域儲存在同一個位元組中,如一個位元組所剩空間不夠存放另一位域時,則會從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bs{ unsigned a:4; unsigned :4; /* 空域 */ unsigned b:4; /* 從下一單元開始存放 */ unsigned c:4 }
在這個位域定義中,a 佔第一位元組的 4 位,後 4 位填 0 表示不使用,b 從第二位元組開始,佔用 4 位,c 佔用 4 位。
位域的寬度不能超過它所依附的資料型別的長度,
位域可以是無名位域,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
struct k{ int a:1; int :2; /* 該 2 位不能使用 */ int b:3; int c:2; };
位域的使用
位域的使用和結構成員的使用相同,其一般形式為:
位域變數名.位域名
位域變數名->位域名
位域允許用各種格式輸出。
#include<stdio.h> int main() { struct bs { unsigned a : 1; unsigned b : 3; unsigned c : 4; } bit, * pbit; bit.a = 1; /* 給位域賦值(應注意賦值不能超過該位域的允許範圍) */ bit.b = 7; /* 給位域賦值(應注意賦值不能超過該位域的允許範圍) */ bit.c = 15; /* 給位域賦值(應注意賦值不能超過該位域的允許範圍) */ printf("%d,%d,%d\n", bit.a, bit.b, bit.c); /* 以整型量格式輸出三個域的內容 */ pbit = &bit; /* 把位域變數 bit 的地址送給指標變數 pbit */ pbit->a = 0; /* 用指標方式給位域 a 重新賦值,賦為 0 */ pbit->b &= 3; /* 使用了複合的位運算子 "&=",相當於:pbit->b=pbit->b&3,位域 b 中原有值為 7,與 3 作按位與運算的結果為 3(111&011=011,十進位制值為 3) */ pbit->c |= 1; /* 使用了複合位運算子"|=",相當於:pbit->c=pbit->c|1,其結果為 15 */ printf("%d,%d,%d\n", pbit->a, pbit->b, pbit->c); /* 用指標方式輸出了這三個域的值 */ }
1, 7, 15 0, 3, 15結果