C :位域實現與對齊

C/C++中以一定區域內的位(bit)爲單位來表示的數據成爲位域,位域必須指明具體的數目。位域的作用主要是節省內存資源,使數據結構更緊湊。

REF:   https://www.cnblogs.com/pure/archive/2013/04/22/3034818.html

位數組 : https://blog.csdn.net/qq_37375427/article/details/79797359


C/C++中以一定區域內的位(bit)爲單位來表示的數據成爲位域,位域必須指明具體的數目。

位域的作用主要是節省內存資源,使數據結構更緊湊。

     有些信息在存儲時,並不需要佔用一個完整的字節, 而只需佔幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。爲了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱爲“位域”或“位段”。所謂“位域”是把一個字節的二進位劃分爲幾個不同的區域, 並說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作 

 

  • 一個位域必須存儲在同一個字節中,不能跨兩個字節,故位域的長度不能大於一個字節的長度;

struct BitField

{

      unsigned int a:4;  //佔用4個二進制位;

      unsigned int  :0;  //空位域,自動置0;

      unsigned int b:4;  //佔用4個二進制位,從下一個存儲單元開始存放;

      unsigned int c:4;  //佔用4個二進制位;

      unsigned int d:5;  //佔用5個二進制位,剩餘的4個bit(e)不夠存儲4個bit的數據,從下一個存儲單元開始存放;

      unsigned int  :0;  //空位域,自動置0;

      unsigned int e:4;  //佔用4個二進制位,從這個存儲單元開始存放;

};

  • 取地址操作符&不能應用在位域字段上;

  • 位域字段不能是類的靜態成員;

  • 位域字段在內存中的位置是按照從低位向高位的順序放置的;

  • 位域的對齊

1. 如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則後面的字段將緊鄰前一個字段存儲,直到不能容納爲止;

2. 如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則後面的字段將從新的存儲單元開始,其偏移量爲其類型大小的整數倍;

3.如果相鄰的兩個位域字段的類型不同,則各個編譯器的具體實現有差異,VC6採取不壓縮方式,GCC和Dev-C++都採用壓縮方式;

4. 整個結構體的總大小爲最寬基本類型成員大小的整數倍。

5. 如果位域字段之間穿插着非位域字段,則不進行壓縮;(不針對所有的編譯器)

 

TIP:

  • 位域變量的地址不可取

 

位域與大小端: 大端和小端都是以字節爲準的。大端即高字節在低地址。

 

位域與符號:

union

{

    struct

    {

        char a:1;

        char b:2;

        unsigned char c:5;

    }d;

    unsigned char e;

}f;

    f.d.b = 0x01;

    printf("e = %x, %d\n",f.e,f.e);

    printf("a = %x, %d\n",f.d.a,f.d.a);

    printf("b = %x, %d\n",f.d.b,f.d.b);

 

            b                     e

0x01  0001  1 (0000 0001)    0010 2

0x02  0010 -2 (1111 1110)    0100 4

0x03  0011 -1 (1111 1111)    0110 6  最高位分得1,就是負數,負數用的補碼.

                                     實際的值是取反加1,就是00+1=1,再取符號負數,就是-1.

0x04  0100  OUT   ...... 不能給 b 賦值 b 只有兩個bit (0~3)

 

注:

無符號整型在循環條件中造成死循環

#include<stdio.h>

int main()

{

    size_t i = 10;

    while(i >= 0)

    {

        printf("%u\t", i);

        i--;               /* 當 i 爲 0 時, i-- 操作導致下溢翻轉,變成該整型所能表示的最大值而導致死循環 */

    }

    return 0;

}

對於無符號整數類型(unsigned char, unsigned short , unsigned int, unsigned long 以及宏定義 size_t 等),執行自減操作就會下溢而翻轉,變成該整型的最大值,從而導致死循環的發生。

避免這種錯誤最簡單的方式就是不要用無符號整數執行自減運算時與 0 進行相等比較;或者避免使用無符號整型進行此類操作。對於示範代碼,將 ”size_t“  改成 ”int", 或者修改 “ while(i >= 0)" 爲 " while(i > 0)"的判斷(當然判斷條件的意思也變了)。

大正整數相加上溢,大負整數相減下溢

a = 2147483647,   a + 1 = -2147483648

b = -2147483648,  b - 1 = 2147483647

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章