內存對齊原則

內存對齊原則:
一、結構體變量的首地址能夠被其最寬基本類型成員大小與對齊基數中的較小者所整除;
二、結構體每個成員相對於結構體首地址的偏移量(offset)都是該成員大小與對齊基數中的較小者的整數倍,如有需要編譯器會在成員之間加上填充字節(internal adding);
三、結構體的總大小爲結構體最寬基本類型成員大小與對齊基數中的較小者的整數倍,如有需要編譯器會在最末一個成員之後加上填充字節(trailing padding)。

 

關於結構體分配內存和字節對齊原則
今天看到一個關於sizeof的使用問題,並且提到了計算機組成原理中的字節對齊,寫了如下測試程序,發現了一些問題:

#include <iostream>
#include <malloc.h>
#include <stdlib.h>
using namespace std;

struct S0 {};

struct S1
{
    char a;
    int b;
};

struct S2
{
    int x;
    char y;
};

struct S3
{
    char c1;
    S1 s;
    char c2;
};

int main ()
{

    cout << "Testing S0 ...\n";
    cout << sizeof(S0);
     cout << "\n\n";                                                                                                                                          
    cout << "Testing S1 ...\n";
    cout << sizeof(S1) << endl;
    S1 s1 = {'a', 0x22222222};
    cout << sizeof(s1) << endl;
    cout << &s1 << endl;
    char *p1 = (char*)malloc(sizeof(char)*sizeof(s1));
    memcpy (p1, &s1, sizeof(s1));
    for (int i=0; i<sizeof(s1); i++)
        printf ("%x ",*(p1+i));
    cout << "\n\n";

    cout << "Testing S2 ...\n";
    cout << sizeof(S2) << endl;
    S2 s2 = {0x22222222, 'a'};
    cout << sizeof(s2) << endl;
    cout << &s2 << endl;
    char *p2 = (char*)malloc(sizeof(char)*sizeof(s2));
    memcpy (p2, &s1, sizeof(s2));
    for (int i=0; i<sizeof(s2); i++)
        printf ("%x ",*(p2+i));
    cout << "\n\n";

    cout << "Testing S3 ...\n";
    cout << sizeof(S3) << endl;
    S3 s3 = {'b', s1, 'c'};
    cout << sizeof(s3) << endl;
    cout << &s3 << endl;
    char *p3 = (char*)malloc(sizeof(char)*sizeof(s3));
    memcpy (p3, &s3, sizeof(s3));
    for (int i=0; i<sizeof(s3); i++)
        printf ("%x ",*(p3+i));
    cout << "\n\n";
    return 0;
}

/*-------------------------------------------------------------------------------------------
Eclipse+CDT下運行結果:

Testing S0 ...
1

Testing S1 ...
8
8
0x22ff80
61 0 40 0 22 22 22 22

Testing S2 ...
8
8
0x22ff70
61 0 40 0 22 22 22 22

Testing S3 ...
16
16
0x22ff58
62 ffffffff 22 0 61 0 40 0 22 22 22 22 63 10 40 0
--------------------------------------------------------------------------------------------*/
總結規律發現:
在結構體中每個像出現char這樣佔一個字節的變量後面會自動補上3個字節,使之變爲和int一樣大小的4字節變量。 所以S1和S2就是佔了8字節的內存,S3佔了16字節的內存。

關於字節對齊:
查閱資料後發現,字節對齊有助於加快計算機的取數速度,否則就得多花指令週期了。爲此,編譯器默認會對結構體進行處理(實際上其它地方的數據變量也是如此),讓寬度爲2的基本數據類型(short等)都位於能被2整除的地址上,讓寬度爲4的基本數據類型(int等)都位於能被4整除的地址上,以此類推。這樣,兩個數中間就可能需要加入填充字節,所以整個結構體的sizeof值就增長了。

字節對齊的細節和編譯器實現相關,但一般而言,滿足三個準則:
1) 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除;
2) 結構體每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節(internal adding);
3) 結構體的總大小爲結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之後加上填充字節(trailing padding)。
例如對S3來看:
S3中的S1其實是打散的int和char,所以相當是char,int,char,char,最長的寬度是int爲4字節,所以要保證char也是佔據4字節,所以最終就是總共16字節所示結果。
62 ffffffff 22 0 61 0 40 0 22 22 22 22 63 10 40 0。
恩,搞移動開發對每一byte的內存都很珍惜啊~~~~~嚴重鄙視像Vista這樣沒幹什麼事就耗我七百多兆內存的系統。。
 

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