1. 程式人生 > >C++ 位元組對齊分析,struct成員指定位大小

C++ 位元組對齊分析,struct成員指定位大小

閱讀C++ Concurrency In Action 第5章遇到這個問題,記錄下來,方便以後回頭看

主要涉及 位域位元組對齊問題,位域一般不常見,屬於C/C++高階特性

位域指的是針對struct成員指定位大小,位域的作用主要是節省記憶體資源,使資料結構更緊湊


原書這樣描述:

無論什麼型別,物件均被儲存於一個或多個記憶體位置中,每個這樣的記憶體位置要麼是一個標量型別的物件(或子物件),比如unsigned short 或 my_class*,要麼是相鄰位域的序列。

如果使用位域,有非常重要的一點必須注意:雖然相鄰的位域是不同的物件,但他們仍然算作相同的記憶體位置。

上圖所示的結構體 struct my_data,整個struct是一個物件,它由幾個子物件組成,各子物件對應每個資料成員。

位域bf1和bf2共享一個記憶體位置,而std::string物件在內部由幾個記憶體位置組成,但是其餘的每個成員都有自己的記憶體位置。

注意零長度的位域bf3是如何將bf4分割進它自己的記憶體位置的

開始對上述標紅的位置不是很理解,

查閱資料瞭解,位域儲存具有如下規則:

1、如果相鄰位域欄位的型別相同,且其位寬之和小於這個型別的sizeof大小,則後面的欄位將緊鄰前一個欄位儲存,知道不能容納為止。

2、如果相鄰位域欄位的型別相同,但其位寬之和大雨型別的sizeof大小,則後面的欄位將從新的儲存單元開始,其偏移量為其型別大小整數倍。

3、如果相鄰的位域欄位的型別不同,則各編譯器的具體實現有差異,VC6採取不壓縮方式,GCC和Dev-C++採取壓縮方式。

4、如果位域之間穿插著非位域型別,則不進行壓縮。

5、整個結構體的總大小為最寬基本型別成員大小的整數倍

6、取地址操作符&不能應用在位域欄位上

7、位域欄位不能是類的靜態成員

8、位域欄位在記憶體中的位置是按照從低位向高位的順序放置的

9、當要把某個成員說明成位域時,其型別只能是int,unsigned int與signed int三者之一

根據以上規則,分析該struct佔用位元組書,sizeof(struct my_data) = 48,

分解後應該如下所示:

struct my_data {
    int i;              //對齊後佔用8位元組, 實際使用4位元組
    //空行表示需要開闢新的8位元組記憶體空間
    double d;           //佔用8位元組

    unsigned bf1:10;    //對齊後佔用4位元組,實際使用10 bit
    int bf2:25;         //10+25 > 32,因此佔用新的4位元組,對齊後佔用4位元組,實際使用25 bit
    int bf3:0;          //<span style="color: rgb(0, 128, 0); line-height: 1.5; font-family: "Courier New"; white-space: pre-wrap;">空位域,自動置0</span>
    int bf4:9;          //25+9 > 32,因此需要佔用新的4位元組,對齊後佔用4位元組,實際佔用9bit
    int i2;             //佔用4位元組

    char c1, c2;        //對齊佔用8位元組,實際使用2位元組

    std::string s;      //佔用8位元組
};

其中bf1和bf2型別不同,其實是經過壓縮儲存的,即他們可以緊鄰儲存,

經過測試,將int bf2:25 改成 int bf2:22,則sizeof(struct my_data) = 40,說明bf2是可以緊鄰bf1儲存的,說明是壓縮儲存的。

參考資料

1、http://www.cnblogs.com/hedaihong/p/4348535.html

2、c++併發程式設計實戰

3、http://www.cnblogs.com/pure/archive/2013/04/22/3034818.html