C 結構體中的位域概念

MElephant發表於2024-03-09

位域

一、基本概念

1.1 位域的概念

結構體中的冒號表示位域,如:

struct bit_struct
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:14;
} data1; // sizeof data1 = 4

struct bit_struct
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:16;
} data2; // sizeof data2 = 8

位域出現的原因是由於某些資訊的「儲存表示」只需要幾個 bit 位就可以表示,而不需要一個完整的位元組,同時也是為了節省儲存空間和方便處理。

1.2 說明

  1. 位域必須儲存在同一個型別中,不能跨型別,同時也說明位域的長度不會超過所定義型別的長度。如果一個定義型別單元裡所剩空間無法存放下一個域,則下一個域應該從下一單元開始存放。
    如 data2,所定義的型別是 unsigned int 型別,一共 32 位,bit1 和 bit2 用掉了 18bit,還剩下 \(32-18=14bit\),這時要儲存一個 16bit 的位域元素 bit3,那麼這個元素就只能從下一個 unsigned int 型別的單元開始而不會在前面一個unsigned int 型別中佔 14bit 後面的 unsigned int 型別中佔 2bit。

  2. 如果位域的位域長度為0表示是個空域,同時下一個域應當從下一個位元組單元開始存放。

  3. 使用無名的位域來作為填充和調整位置,切記該位域是不能被使用的。

  4. 位域的本質上就是一種結構體型別,不同的是其成員是按二進位制位來分配的。

二、程式碼理解

#include <stdio.h>
#include <string.h>

struct bit_struct_1
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:14;
} data1; // sizeof data1 = 4

struct bit_struct_2
{
    unsigned int  bit1:10;
    unsigned int  bit2:8;
    unsigned int  bit3:16;
} data2; // sizeof data2 = 8


/*
 0001 1001 0010 1010 1011 0011 0100 1111 0101 1101 0110 1100 0111 1110 1000 1011
 ————————— ————————— ————————— ————————— ————————— ————————— ————————— —————————
    19        2A        B3        4F         5D        6C       8E        9B
    高 <-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·- 低
*/
int main()
{
    unsigned long long ullNum = 0x192AB34F5D6C7E8B;
    memcpy(&data1, (void *)&ullNum, sizeof(data1));
    memcpy(&data2, (void *)&ullNum, sizeof(data2));

    printf("data1 size is %d\n", sizeof(data1));  /* size is 4 */
    printf("[1] bit1 : %u\n", data1.bit1);          /* 651  --> 1010001011 */
    printf("[1] bit2 : %u\n", data1.bit2);          /* 31   --> 00011111 */
    printf("[1] bit3 : %u\n", data1.bit3);          /* 5979 --> 01011101011011 */

    puts("------------------------");
    printf("data2 size is %d\n", sizeof(data2));  /* size is 8 */
    printf("[2] bit1 : %u\n", data2.bit1);          /* 651   --> 1010001011 */
    printf("[2] bit2 : %u\n", data2.bit2);          /* 31    --> 00011111 */
    printf("[2] bit3 : %u\n", data2.bit3);          /* 45903 --> 1011001101001111 */

    return 0;
}

上述程式碼中我們定義了一個 8B 的 ullNum,其二進位制表示如下圖所示:

image-20240309161334183

從低位元組到高位元組分別分配給 bit1、bit2、bit3 :

image-20240309162313180

參考資料

  • C語言結構體中的冒號的作用_c語言結構體中的冒號用法-CSDN部落格

相關文章