1. 程式人生 > 其它 >C語言:位域

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
結果

參考

菜鳥教程