全攻略有點大放厥詞,嘩眾取寵了,其實是一些常見的問題罷了。但是自認為總結的還算全面一點吧,請大家多多賜教,我只是個初學者。

接下來主要討論四點:
一、不涉及位域的內存對齊原則
二、涉及位域的內存對其原則
三、成員變量含有結構體的內存對齊情況
四、要求內存對齊的原因及優點

引子:
 1#include <iostream>
 2using namespace std;
 3struct A
 4
 5    char m; 
 6    int n; 
 7}
;
 8int main ()
 9
10    A a; 
11    a.m=1;a.n=2;
12    printf("sizeof(A)=%d\nsizeof(A.m)=%d\nsizeof(A.n)=%d\n",sizeof(a),sizeof(a.m),sizeof(a.n)); 
13    return 0;
14}

預測輸出:
sizeof(A)=5
sizeof(A.m)=1
sizeof(A.n)=4
實際輸出:

分析:
也許該疑問了,sizeof(A.m)=1,sizeof(A.n)=4,sizeof(A)不是該1+4=5嗎,怎么是8呢?

這是因為程序員眼中的內存與處理機處理內存的不一致,請看下圖:
程序員通常認為內存就是一些列簡單的字節數組,在C語言以及它的衍生語言中,char*被普遍認為代表一塊內存區域,即使是Java也用byte[]來代表原始內存如下圖所示:

處理機在對內存進行存取操作時,卻不是以單個字節為單位來進行的,它通常是以2 、4、 8 、16大小的字節塊來進行的。我們稱處理器訪問內存時一次存取的內存大小為存訪問粒度”,如下圖所示:


可以看一下內存中的情況,確實是8個字節:


一、不涉及位域的內存對齊原則
規則如下,然后來舉例說明:
1)對結構的數據成員,第一個數據成員位于偏移為0的位置,以后每個數據成員的偏移量必須是MIN(#pragma pack()指定的數,此數據成員的自身長度) 的倍數,我們稱MIN(#pragma pack()指定的數,此數據成員的自身長度) 為該結構成員的對齊模數。
注:程序中通常是不指定#pragma pack()它的,默認值為8,從哪里可以看到呢,看下圖(發現用圖說話有時是直觀方便易懂……):


2)為結構體的一個成員開辟空間之前,編譯器首先檢查預開辟空間的首地址相對于結構體首地址的偏移是否是本成員的整數倍,若是,則存放本成員,反之,則在本成員和上一個成員之間填充一定的字節(填充字節為CC,也就是int3中斷),以達到整數倍的要求,也就是將預開辟空間的首地址后移幾個字節。


3)在數據成員完成各自對齊之后,結構(或聯合)本身也要進行對齊,對齊將按照MIN(指定的#pragma pack()的數值,MAX(結構(或聯合)數據成員長度))進行對齊。

這部分以這段代碼為例:
 1#include <iostream>
 2using namespace std;
 3struct A
 4
 5    char c; 
 6    int i; 
 7    short s;
 8}
;
 9int main ()
10
11    A a; 
12    a.c=1;a.i=2;a.s=3;
13    printf("sizeof(A)=%d\n",sizeof(A)); 
14    return 0;
15}
這里,我們采用系統默認的#pragma pack(8),則
c 的對齊模數為:MIN(sizeof(char),8)=MIN(1,8)=1
i  的對齊模數為:MIN(sizeof(int),8)=MIN(4,8)=4
s 的對齊模數為:MIN(sizeof(short),8)=MIN(2,8)=2
根據規則一:

根據規則二:
當給c開辟空間以后,為i開辟空間之前,編譯器先檢查與開辟空間的首地址,發現為1,不是i的對齊模數的整數倍,則向后找,一直到地址4時,以4為起始,向后開辟四個字節大小的空間,而之前的1,2,3這三處則填充 CC ,如下圖:

根據規則三:
現在進行結構體對齊,整個sizeof(A)=10,而MIN(8,MAX(sizeof(c),sizeof(i),sizeof(s)))=4,則sizeof(A)=MIN(4N),并且sizeof(A)>=10,故,sizeof(A)=12.再將10,11空間給填充上CC:

要知道為什么有的是CC,有的是00啊,還有,千萬別看到sizeof(A)=12,就把12位置也給填上CC啊

本來打算寫一篇嘮叨完,但我太絮叨了,一個問題說了這么多,分開寫吧……