結(jié)構(gòu)體字節(jié)對(duì)齊

一、為什么結(jié)構(gòu)體內(nèi)存對(duì)齊

其實(shí)我們都知道,結(jié)構(gòu)體只是一些數(shù)據(jù)的集合然爆,它本身什么都沒(méi)有投蝉。我們所謂的結(jié)構(gòu)體地址枚尼,其實(shí)就是結(jié)構(gòu)體第一個(gè)元素的地址。這樣,如果結(jié)構(gòu)體各個(gè)元素之間不存在內(nèi)存對(duì)齊問(wèn)題,他們都挨著排放的向挖。對(duì)于32位機(jī),32位編譯器(這是目前常見的環(huán)境炕舵,其他環(huán)境也會(huì)有內(nèi)存對(duì)齊問(wèn)題)何之,就很可能操作一個(gè)問(wèn)題,就是當(dāng)你想要去訪問(wèn)結(jié)構(gòu)體中的一個(gè)數(shù)據(jù)的時(shí)候咽筋,需要你操作兩次數(shù)據(jù)總線溶推,因?yàn)檫@個(gè)數(shù)據(jù)卡在中間,如圖:

在上圖中奸攻,對(duì)于第2個(gè)short數(shù)據(jù)進(jìn)行訪問(wèn)的時(shí)候悼潭,在32位機(jī)器上就要操作兩次數(shù)據(jù)總線。這樣會(huì)非常影響數(shù)據(jù)讀寫的效率舞箍,所以就引入了內(nèi)存對(duì)齊的問(wèn)題。另外一層原因是:某些硬件平臺(tái)只能從規(guī)定的地址處取某些特定類型的數(shù)據(jù)皆疹,否則會(huì)拋出硬件異常疏橄。

二、結(jié)構(gòu)體內(nèi)存對(duì)齊的規(guī)則

下表是Windows XP/DEV-C++和Linux/GCC中基本數(shù)據(jù)類型的長(zhǎng)度和默認(rèn)對(duì)齊模數(shù)略就。

char short int long float double long long long double
Win-32 長(zhǎng)度 1 2 4 4 4 8 8 8
Linux-32 長(zhǎng)度 1 2 4 4 4 8 8 12
Linux-64 長(zhǎng)度 1 2 4 8 4 8 8 16
MAC-64 長(zhǎng)度 1 2 4 8 4 8 8 16

1.未指定#pragma pack時(shí)

a.第一個(gè)成員起始于0偏移處捎迫;
b.每個(gè)成員按其類型大小和指定對(duì)齊參數(shù)n中較小的一個(gè)進(jìn)行對(duì)齊;
c.結(jié)構(gòu)體總長(zhǎng)度必須為所有對(duì)齊參數(shù)的整數(shù)倍,或者理解為最大類型的整數(shù)倍表牢;
d.對(duì)于數(shù)組窄绒,可以拆開看做n個(gè)數(shù)組元素。

2.指定#pragma pack(n)時(shí)

a. n必須為0 1 2 4 8 16崔兴,其中為0時(shí)就相當(dāng)于未指定#pragma pack
b. 當(dāng)結(jié)構(gòu)體中的類型小于n時(shí)彰导,按該類型的對(duì)齊規(guī)則對(duì)齊,對(duì)于大于等于n的類型敲茄,按n對(duì)齊位谋。
c.結(jié)構(gòu)體總長(zhǎng)度: 1.當(dāng)結(jié)構(gòu)體中的類型全都小于n時(shí),總長(zhǎng)度為所有對(duì)齊參數(shù)的整數(shù)倍,或者理解為最大類型的整數(shù)倍堰燎;2.當(dāng)結(jié)構(gòu)體中有大于等于n的類型掏父,按n的整數(shù)倍對(duì)齊。

三秆剪、具體舉例 運(yùn)行環(huán)境為MAC-64

1.未指定#pragma pack時(shí)

例1
struct S1
{

    short a1;
    short a2;
    short a3;

};
struct S2
{
    long a1;
    short a2;
};

打印結(jié)果為 size of s1:6 -- size of s2:16
sizeof(S1) = 6; 這個(gè)很好理解赊淑,三個(gè)short都為2爵政。

例2
struct S1{
  int a;
  char b;
  short c;
};

struct S2{
  char b;
  int a;
  short c;
};

打印結(jié)果:size of s1:8 -- size of s2:12


字節(jié)對(duì)齊示意圖

上圖中一個(gè)單元格表示一個(gè)字節(jié) 1表示占用,0表示空閑
由上圖可以看出要按類型字節(jié)長(zhǎng)度的整數(shù)倍位置對(duì)齊陶缺,其他位置被空閑钾挟。最終所占長(zhǎng)度為最大類型的整數(shù)倍。

  1. S1中a 占4個(gè)字節(jié)组哩。b占1個(gè)字節(jié)等龙,c占2個(gè)字節(jié),但是c要從2的倍數(shù)處對(duì)齊伶贰,因此蛛砰,正好S1占8個(gè)字節(jié),是所有類型的整數(shù)倍黍衙,占8個(gè)字節(jié)泥畅。
  2. S2中b占1個(gè)字節(jié) 占0位置,a 占4個(gè)字節(jié) 從索引4開始對(duì)齊琅翻,c占2個(gè)字節(jié) 從索引8開始對(duì)齊位仁,總長(zhǎng)為10,但是整個(gè)空間應(yīng)該為所有類型的整數(shù)倍方椎,因此需要2個(gè)空閑位聂抢。總共12個(gè)字節(jié)
例3 下面是結(jié)構(gòu)體嵌套情況
struct S1{
     int a;
     double b;
     float c;
};

struct S2{
     char e[2];
     int f;
     double g;
     short h;
     struct S1 s;
};

打印結(jié)果:size of s1:24 -- size of s2:48
sizeof(S1) = 24; 這個(gè)比較好理解棠众,int為4琳疏,double為8,float為4闸拿,總長(zhǎng)為8的倍數(shù)空盼,補(bǔ)齊,所以整個(gè)S1為24新荤。
我們看看S2的內(nèi)存布局:

e f g h s
1 1 * * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 * * * * * * 1111**** 11111111 11******

s 為結(jié)構(gòu)體S1 看做一個(gè)整體揽趾,他的最大類型double為8位 需要按8的倍數(shù)對(duì)齊,因此從索引24開始 因此總共48位

例4
struct S1
{
  short a;
  int b;
};

struct S2
{
    char c;
    struct S1 d;
    double e;
};

打印結(jié)果:size of s1:8 -- size of s2:24
內(nèi)存布局如下:

S1 a b
1 1 * * 1 1 1 1
S2 c d e
1 * * * 11** 1111 * * * * 1 1 1 1 1 1 1 1

綜上可知

在結(jié)構(gòu)體嵌套的情況下 結(jié)構(gòu)體看做一個(gè)整體苛骨,他按他自己的最大成員的類型進(jìn)行對(duì)齊篱瞎,最終按整個(gè)結(jié)構(gòu)體中最大類型對(duì)齊。

指定#pragma pack(n)時(shí)(#pragma pack 是編譯預(yù)處理指令痒芝,可以指定按多少字節(jié)對(duì)齊)

a. n必須為0 1 2 4 8 16奔缠,其中為0時(shí)就相當(dāng)于未指定#pragma pack
b. 當(dāng)結(jié)構(gòu)體中的類型小于n時(shí),按該類型的對(duì)齊規(guī)則對(duì)齊吼野,對(duì)于大于等于n的類型校哎,按n對(duì)齊。
c.結(jié)構(gòu)體總長(zhǎng)度: 1.當(dāng)結(jié)構(gòu)體中的類型全都小于n時(shí),總長(zhǎng)度為所有對(duì)齊參數(shù)的整數(shù)倍,或者理解為最大類型的整數(shù)倍闷哆;
2.當(dāng)結(jié)構(gòu)體中有大于等于n的類型腰奋,按n的整數(shù)倍對(duì)齊。

例1
#pragma pack(1)
struct S1
{
    char  a;
    short b;
    short c;

};
struct S2
{
    long d;
    short e;
    char f;
};

打印結(jié)果為:size of s1:5 -- size of s2:11
很好理解n=1時(shí)抱怔,按順序排放

pragma pack(2) 時(shí)的結(jié)果:size of s1:6 -- size of s2:12
此時(shí) S1中的short類型正好等于2個(gè)字節(jié) 因此按2個(gè)字節(jié)對(duì)齊劣坊,S2中l(wèi)ong類型占8字節(jié)大于2 因此按2字節(jié)對(duì)齊

pragma pack(4) 時(shí)的結(jié)果: size of s1:6 -- size of s2:12
此時(shí)S1中的所有類型長(zhǎng)度都小于4,因此按S1中最大類型short對(duì)齊屈留。S2中l(wèi)ong類型占8字節(jié)大于4 因此按4字節(jié)對(duì)齊

pragma pack(8) 時(shí)的結(jié)果:size of s1:6 -- size of s2:16
此時(shí)S1中的所有類型長(zhǎng)度都小于8局冰,因此按S1中最大類型short對(duì)齊。
S2中l(wèi)ong類型占8字節(jié)正好等于8 因此按8字節(jié)對(duì)齊灌危,因此為16字節(jié)

pragma pack(16) 時(shí)的結(jié)果:size of s1:6 -- size of s2:16
此時(shí)S1還是所有類型小于16康二,因此按S1中最大類型short對(duì)齊。
S2中l(wèi)ong類型占8字節(jié)小于16 因此按S2中最大類型long 8字節(jié)對(duì)齊勇蝙,因此為16字節(jié).

例2 結(jié)構(gòu)體嵌套情況
#pragma pack(1)
struct S1
{
  short a;
  int b;
};

struct S2
{
    char c;
    struct S1 d;
    double e;
};

打印結(jié)果:size of s1:6 -- size of s2:15
很好理解所有結(jié)構(gòu)體順序排放

pragma pack(2) 的時(shí)候:size of s1:6 -- size of s2:16
S1還是6字節(jié)沫勿。
S2的布局情況如下

S2 c d e
1 * 11 1111 11111111

pragma pack(4) 的時(shí)候: size of s1:8 -- size of s2:20
此時(shí)S1中的int類型正好是4 因此按4字節(jié)對(duì)齊 因此占8字節(jié)
S2的內(nèi)存布局如下:

S2 c d e
1 *** 11**1111 11111111

此時(shí)因?yàn)閐是S1類型 S1看做一個(gè)整體,在S1中按4字節(jié)對(duì)齊 因此從4開始布局,e由于大于pack(4) 因此按4字節(jié)對(duì)齊排序味混,從12索引出開始布局产雹。因此總共20字節(jié) 也是4的整數(shù)倍。

pragma pack(8) 的時(shí)候: size of s1:8 -- size of s2:24
此時(shí)S1中的int類型小于8翁锡,因此按S1中最大類型int對(duì)齊
S2的內(nèi)存布局如下:

S2 c d e
1 *** 11**1111 **** 11111111

此時(shí)S2中最大類型(double)的成員e正好等于8蔓挖,因此按8字節(jié)對(duì)齊,因此從索引16出開始布局馆衔,最終為24個(gè)字節(jié)

pragma pack(16) 的時(shí)候: size of s1:8 -- size of s2:24
此時(shí)S2中最大類型(double)成員e小于16时甚,因此按8字節(jié)對(duì)齊,因此情況和pragma pack(8) 的時(shí)候一樣哈踱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市梨熙,隨后出現(xiàn)的幾起案子开镣,更是在濱河造成了極大的恐慌,老刑警劉巖咽扇,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邪财,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡质欲,警方通過(guò)查閱死者的電腦和手機(jī)树埠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)嘶伟,“玉大人怎憋,你說(shuō)我怎么就攤上這事。” “怎么了绊袋?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵毕匀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我癌别,道長(zhǎng)皂岔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任展姐,我火速辦了婚禮躁垛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘圾笨。我一直安慰自己教馆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布墅拭。 她就那樣靜靜地躺著活玲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谍婉。 梳的紋絲不亂的頭發(fā)上舒憾,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音穗熬,去河邊找鬼镀迂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛唤蔗,可吹牛的內(nèi)容都是我干的探遵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼妓柜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼箱季!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起棍掐,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤藏雏,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后作煌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掘殴,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年粟誓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奏寨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鹰服,死狀恐怖病瞳,靈堂內(nèi)的尸體忽然破棺而出揽咕,到底是詐尸還是另有隱情,我是刑警寧澤仍源,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布心褐,位于F島的核電站,受9級(jí)特大地震影響笼踩,放射性物質(zhì)發(fā)生泄漏逗爹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一嚎于、第九天 我趴在偏房一處隱蔽的房頂上張望掘而。 院中可真熱鬧,春花似錦于购、人聲如沸袍睡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)斑胜。三九已至,卻和暖如春嫌吠,著一層夾襖步出監(jiān)牢的瞬間止潘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工辫诅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凭戴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓炕矮,卻偏偏與公主長(zhǎng)得像么夫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肤视,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容