《c專家編程》筆記–linux記憶體對齊

來源:互聯網
上載者:User

在最近的項目中,我們涉及到了“記憶體對齊”技術。對於大部分程式員來說,“記憶體對齊”對他們來說都應該是“透明的”。“記憶體對齊”應該是編譯器的 “管轄範圍”。編譯器為程式中的每個“資料單元”安排在適當的位置上。但是C語言的一個特點就是太靈活,太強大,它允許你幹預“記憶體對齊”。如果你想瞭解 更加底層的秘密,“記憶體對齊”對你就不應該再透明了。

一、記憶體對齊的原因

大部分的參考資料都是如是說的:

1、平台原因(移植原因):不是所有的硬體平台都能訪問任意地址上的任意資料 的;某些硬體平台只能在某些地址處取某些特定類型的資料,否則拋出硬體異常。

2、效能原因:資料結構(尤其是棧)應該儘可能地在常態範圍上對齊。 原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。

二、對齊規則

每個特定平台上的編譯器都有自己的預設“對齊係數”(也叫對齊模數)。程式員可以通過先行編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一係數,其中的n就是你要指定的“對齊係數”。

規則:

1、資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第一個資料成員放在offset為0的地方,以後 每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。

2、結構(或聯合)的整體對齊規則:在 資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。

3、結合1、2顆推斷:當#pragma pack的n值等於或超過所有資料成員長度的時候,這個n值的大小將不產生任何效果。

三、實驗

我們通過一系列例子的詳細說明來證明這個規則吧!

我實驗用的編譯器是GCC 4.4.6

我們將用典型的struct對齊來說明。首先我們定義一個struct:

#pragma pack(n) /* n = 1, 2, 4, 8, 16 */

struct test_t {

 int a;

 char b;

 short c;

 char d;

};

#pragma pack(n)

首先我們首先確認在實驗平台上的各個類型的size,經驗證兩個編譯器的輸出均為:

sizeof(char) = 1

sizeof(short) = 2

sizeof(int) = 4

我們的實驗過程如下:通過#pragma pack(n)改變“對齊係數”,然後察看sizeof(struct test_t)的值。

1、1位元組對齊(#pragma pack(1))

輸出結果:sizeof(struct test_t) = 8

分析過程:

1) 成員資料對齊

#pragma pack(1)

struct test_t {

 int a;  /* 長度4 < 1 按1對齊;起始offset=0;存放位置區間[0,3] */

 char b;  /* 長度1 = 1 按1對齊;起始offset=4;存放位置區間[4] */

 short c; /* 長度2 > 1 按1對齊;起始offset=5;存放位置區間[5,6] */

 char d;  /* 長度1 = 1 按1對齊;起始offset=7;存放位置區間[7] */

};

#pragma pack()

成員總大小=8

2) 整體對齊

整體對齊係數 = min((max(int,short,char), 1) = 1

2、2位元組對齊(#pragma pack(2))

輸出結果:sizeof(struct test_t) = 10

分析過程:

1) 成員資料對齊

#pragma pack(2)

struct test_t {

 int a;  /* 長度4 > 2 按2對齊;起始offset=0;存放位置區間[0,3] */

 char b;  /* 長度1 < 2 按1對齊;起始offset=4;存放位置區間[4] */

 short c; /* 長度2 = 2 按2對齊;起始offset=6;存放位置區間[6,7] */

 char d;  /* 長度1 < 2 按1對齊;起始offset=8;存放位置區間[8] */

};

#pragma pack()

成員總大小=9

2) 整體對齊

整體對齊係數 = min((max(int,short,char), 2) = 2

3、4位元組對齊(#pragma pack(4))

輸出結果:sizeof(struct test_t) = 12

分析過程:

1) 成員資料對齊

#pragma pack(4)

struct test_t {

 int a;  /* 長度4 = 4 按4對齊;起始offset=0;存放位置區間[0,3] */

 char b;  /* 長度1 < 4 按1對齊;起始offset=4;存放位置區間[4] */

 short c; /* 長度2 < 4 按2對齊;起始offset=6;存放位置區間[6,7] */

 char d;  /* 長度1 < 4 按1對齊;起始offset=8;存放位置區間[8],最後還要補上3個空位,以滿足總長度是4(int是4個位元組,4=4)的整數倍*/

};

#pragma pack()

成員總大小=9

2) 整體對齊

整體對齊係數 = min((max(int,short,char), 4) = 4

4、8位元組對齊(#pragma pack(8))

輸出結果:sizeof(struct test_t) = 12

分析過程:

1) 成員資料對齊

#pragma pack(8)

struct test_t {

 int a;  /* 長度4 < 8 按4對齊;起始offset=0;存放位置區間[0,3] */

 char b;  /* 長度1 < 8 按1對齊;起始offset=4;存放位置區間[4] */

 short c; /* 長度2 < 8 按2對齊;起始offset=6;存放位置區間[6,7] */

 char d;  /* 長度1 < 8 按1對齊;起始offset=8;存放位置區間[8] 最後還要補上3個空位,以滿足總長度是4(int是4個位元組,4<8)的整數倍*/

};

#pragma pack()

成員總大小=9

2) 整體對齊

整體對齊係數 = min((max(int,short,char), 8) = 4



5、16位元組對齊(#pragma pack(16))

輸出結果:sizeof(struct test_t) = 12

分析過程:

1) 成員資料對齊

#pragma pack(16)

struct test_t {

 int a;  /* 長度4 < 16 按4對齊;起始offset=0;存放位置區間[0,3] */

 char b;  /* 長度1 < 16 按1對齊;起始offset=4;存放位置區間[4] */

 short c; /* 長度2 < 16 按2對齊;起始offset=6;存放位置區間[6,7] */

 char d;  /* 長度1 < 16 按1對齊;起始offset=;存放位置區間[8] 最後還要補上3個空位,以滿足總長度是4(int是4個位元組,4<8)的整數倍 */

};

#pragma pack()

成員總大小=9

2) 整體對齊

整體對齊係數 = min((max(int,short,char), 16) = 4

寫在最後:

如果結構體中有數組,對齊時不會將數組作為一個整體來對齊,而是將數組中個每個元素一個一個來進行對齊。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.