結構體中內存對齊


1.結構體為什么要內存對齊(也叫字節對齊):

其實我們都知道,結構體只是一些數據的集合,我們所說的結構體地址,其實就是結構體第一個元素的地址。這樣,如果結構體各個元素之間不存在內存對齊問題,他們都挨着排放的。對於32位機,32位編譯器(這是目前常見的環境,其他環境也會有內存對齊問題),就很可能操作一個問題,就是當你想要去訪問結構體中的一個數據的時候,需要你操作兩次數據總線,因為這個數據卡在中間,如圖:

結構體中內存對齊

在上圖中,對於第2個short數據進行訪問的時候,在32位機器上就要操作兩次數據總線。這樣會非常影響數據讀寫的效率,所以就引入了內存對齊的

2.內存對齊的規則:

a.第一個成員起始於0偏移處

b.每個成員按其類型大小和指定對齊參數n中較小的一個進行對齊

c.結構體總長度必須為所有對齊參數的整數倍

d.對於數組,可以拆開看做n個數組元素

3.來幾個小例子,畫畫圖,有助於理解:

第一個例子,代碼如下:

#include <stdio.h>
struct _tag_str1
{
  char a;
  int b;
  short c;
}str1;
struct _tag_str2
{
  char a;
  short c;
  int b;
}str2;
int main()
{
  printf("sizeof str1 %d",sizeof(str1));
  printf("sizeof str2 %d",sizeof(str2));
  return 0;
}

 

輸出的結果分別是:str1為12 str2為8,分析的過程如下圖:

結構體中內存對齊

看圖很自然就知道了str1為12個字節,str2為8個字節。

第二個例子,上面的那個例子有好多問題還沒有考慮到,比如說上面的那個例子在8字節對齊,和4字節對齊的情況都是一樣的。結構體中嵌套結構體的內存對齊怎么算,所以就有了這個例子,代碼如下:

#include <stdio.h>
#pragma pack(8)
//#pragma pack(4)
struct S1
{
    short a;
  long b;
};
struct S2
{
    char c;
    struct S1 d;
    double e;
};
#pragma pack()
int main()
{
    struct S2 s2;
    printf("%d", sizeof(struct S1));
    printf("%d", sizeof(struct S2));
    printf("%d", (int)&(s2.d) - (int)&(s2.c));
    return 0;
}

 

我們分析下在4字節對齊的情況下輸出的是,S2是20,S1是8,分析如圖:

結構體中內存對齊

在4字節對齊的情況中,有一個問題值得注意:就是圖中畫1的地方。這里面本應short是可以上去的。但是對於結構體中的結構體一定要十分警惕,S1是一體的,short已經由於long進行了內存對齊,后面還空了兩個字節的內存,其實此時的short已經變成了4個字節了!!!即結構體不可拆,不管是多少字節對齊,他們都是一體的。所有的圈都變成了叉。所以說結構體只能往前篡位置,不能改變整體。

我們在分析一些8字節對齊的情況,如圖:

結構體中內存對齊

同樣,到這里又有一個字節對齊的原則要好好重申一下:就是以什么為對齊參數,首先我們要知道編譯器或者自己定義的是多少字節對齊的,這個數為n。然后我們要看這個結構體中的各個數據類型,找到所占字節數最大的類型,為m。如果n大於m,就以m為對齊參數,比如說一個4字節對齊的結構體中都是short,那這個結構體以什么為對齊參數,當然是2了,如果m大於n,就以n為對齊參數,比如說在4字節對齊的情況下的double類型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM