細說 #pragma pack(n)

來源:互聯網
上載者:User

在C語言中,結構是一種複合資料型別,其構成元素既可以是基礎資料型別 (Elementary Data Type)(如int、long、float等)的變數,也可以是一些複合資料型別(如數組、結構、聯合等)的資料單元。在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間。各個成員按照它們被聲明的順序在記憶體中順序儲存,第一個成員的地址和整個結構的地址相同。

例如,下面的結構各成員空間分配情況:
struct test
{
     char x1;
     short x2;
     float x3;
     char x4;
};

結 構的第一個成員x1,其位移地址為0,佔據了第1個位元組。第二個成員x2為short類型,其起始地址必須2位元組 對界,因此,編譯器在x2和x1之間填充了一個空位元組。結構的第三個成員x3和第四個成員x4恰好落在其自然對界地址上,在它們前面不需要額外的填充字 節。在test結構中,成員x3要求4位元組對界,是該結構所有成員中要求的最大對界單元,因而test結構的自然對界條件為4位元組,編譯器在成員x4後面 填充了3個空位元組。整個結構所佔據空間為12位元組。

更改C編譯器的預設位元組對齊
在預設情況下,C編譯器為每一個變數或是資料單元按其自然對界條件分配空間。一般地,可以通過下面的方法來改變預設的對界條件:
     · 使用偽指令#pragma pack (n),C編譯器將按照n個位元組對齊。
     · 使用偽指令#pragma pack (),取消自訂位元組對齊。

另外,還有如下的一種方式:
     · __attribute((aligned (n))),讓所作用的結構成員對齊在n位元組常態範圍上。如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
     · __attribute__ ((packed)),取消結構在編譯過程中的最佳化對齊,按照實際佔用位元組數進行對齊。

以上的n = 1, 2, 4, 8, 16... 第一種方式較為常見。

下面有一道在 CSDN論壇 上討論火熱的題:

Intel和微軟等公司同時出現的面試題

#pragma pack(8)

struct s1{
short a;
long b;
};

struct s2{
char c;
s1 d;
long long e;
};

#pragma pack()


1.sizeof(s2) = ?
2.s2的c後面空了幾個位元組接著是d?

感謝 redleaves(ID最吊的網友) 的解答,結果如下:

sizeof(S2)結果為24.
成員對齊有一個重要的條件,即每個成員分別對齊.即每個成員按自己的方式對齊.
也就是說上面雖然指定了按8位元組對齊,但並不是所有的成員都是以8位元組對齊.其對齊的規則是,每個成員按其類型的對齊參數(通常是這個類型的大小)和指定對齊參數(這裡是8位元組)中較小的一個對齊.並且結構的長度必須為所用過的所有對齊參數的整數倍,不夠就補空位元組.
S1中,成員a是1位元組預設按1位元組對齊,指定對齊參數為8,這兩個值中取1,a按1位元組對齊;成員b是4個位元組,預設是按4位元組對齊,這時就按4位元組對齊,所以sizeof(S1)應該為8;
S2 中,c和S1中的a一樣,按1位元組對齊,而d 是個結構,它是8個位元組,它按什麼對齊呢?對於結構來說,它的預設對齊就是它的所有成員使用的對齊參數中最大的一個,S1的就是4.所以,成員d就是 按4位元組對齊.成員e是8個位元組,它是預設按8位元組對齊,和指定的一樣,所以它對到8位元組的邊界上,這時,已經使用了12個位元組了,所以又添加了4個位元組 的空,從第16個位元組開始放置成員e.這時,長度為24,已經可以被8(成員e按8位元組對齊)整除.這樣,一共使用了24個位元組.
                          a    b
S1的記憶體布局:11**,1111,
                          c    S1.a S1.b     d
S2的記憶體布局:1***,11**,1111,****11111111

這裡有三點很重要:
1.每個成員分別按自己的方式對齊,並能最小化長度
2.複雜類型(如結構)的預設對齊是它最長的成員的對齊,這樣在成員是複雜類型時,可以最小化長度
3.對齊後的長度必須是成員中最大的對齊參數的整數倍,這樣在處理數組時可以保證每一項都邊界對齊

補充一下,對於數組,比如:
char a[3];這種,它的對齊和分別寫3個char是一樣的.也就是說它還是按1個位元組對齊.
如果寫: typedef char Array3[3];
Array3這種類型的對齊還是按1個位元組對齊,而不是按它的長度.
不論類型是什麼,對齊的邊界一定是1,2,4,8,16,32,64....中的一個.

測試的編譯器:

GCC 2.95 3.1 3.3 3.4 4.0
MS C/C++ 7.0 7.1 8.0 beta
Borland C/C++ 5.6 6.0
Intel C/C++ 7.0 8.0 8.1
DigitalMars C/C++ 8.4
OpenWatcom 1.3
Codeplay C/C++ 2.1.7

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.