字節對齊相關

     C/C++都是按照最大對齊補齊方式的,即按照佔空間最大成員來處理對齊,對齊是由於計算機系統的限制導致的。因爲許多計算機系統對基本數據類型的合法地址做出了一些限制,要求某種類型對象的地址必須是某個值K(通常是2、4或8)的倍數。這種對齊限制簡化了形成處理和內存系統之間接口的硬件設計。

     對齊限制可以提高讀寫內存的效率。例如對double類型數據,有了對齊限制,就可以用一個內存操作來讀或者寫值了,否則可能需要執行兩次內存訪問,因爲對象可能被放在兩個8字節內存塊中。

1. 對齊與補齊

       對齊原則就是任何K字節的基本對象的地址必須是K的倍數。也就是說一個結構體的double成員大小是8字節,則其地址在對齊原則下就必須是8的倍數。下面是各種基本類型對應的K值。

K 類型
1 char
2 short
4 int,float
8 long int,double

         當某個數據類型的地址不滿足對齊原則時,編譯器則會在字段的分配中插入間隙,以滿足每個結構元素都滿足它的對齊要求。例如下面的結構:

typedef struct {
    int a;
    double b;
    char c;
    int d;
    int e;
} A;

        因爲a是4字節,而b是8字節的,則爲了讓b滿足對齊要求,編譯器會在a和b中插入4個字節。因爲c是1字節而d是4字節,則編譯會在c和d之間插入3個字節,從而讓d滿足對齊要求。最後結構體A的空間分配如下:

a 對齊填充
b
c 對齊填充 d
e 對齊填充
               

       PS:最後一行只是爲了表示每行8個字節(去掉的話表格就變形了)。

       如果在C或者C++中調用上面的代碼,可以得到結果爲32,sizeof會將e後面補齊的4個字節也算進去。32是4*8,而8就是結構體A中佔空間最大成員b的字節數。所以在計算佔用空間的時候,要優先考慮到最大的成員字節數。

       注意,指針在32位操作系統中是佔4字節,而在64位系統中佔8字節,這一點在計算的時候需要考慮。

2. #pragma pack()

        對齊限制不是必須的,在C++和C中可以通過宏#pragma pack設置對齊方式。“#pragma pack(K)”是設置對齊方式爲K字節對齊,而“#pragma pack()”則是恢復爲默認的對齊方式。

#include <stdio.h>
#include <stdlib.h>

#pragma pack(1)
typedef struct {
    char a;
    double b;
    char c;
} B;

#pragma pack()
typedef struct {
    int a;
    double b;
    char c;
    int d;
    int e;
} A;

int main()
{
    printf("%d\n", (int)sizeof(A));
    printf("%d\n", (int)sizeof(B));
    return 0;
}

           上面的代碼中,先將結構體B設置爲1字節對齊,然後再將結構體A設置爲默認對齊。最終我們可以得到A結構的大小爲32,而B結構的大小爲10。

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