資源描述:
《CC結(jié)構(gòu)體字節(jié)對(duì)齊詳解.docx》由會(huì)員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在教育資源-天天文庫(kù)。
1、C/C++結(jié)構(gòu)體字節(jié)對(duì)齊詳解注意:成員對(duì)齊有一個(gè)重要的條件,即每個(gè)成員按自己的方式對(duì)齊.其對(duì)齊的規(guī)則是,每個(gè)成員按其類型的對(duì)齊參數(shù)(通常是這個(gè)類型的大小)和指定對(duì)齊參數(shù)(這里默認(rèn)是8字節(jié))中較小的一個(gè)對(duì)齊.并且結(jié)構(gòu)的長(zhǎng)度必須為所用過的所有對(duì)齊參數(shù)的整數(shù)倍,不夠就補(bǔ)空字節(jié).結(jié)構(gòu)體(struct)的sizeof值,并不是簡(jiǎn)單的將其中各元素所占字節(jié)相加,而是要考慮到存儲(chǔ)空間的字節(jié)對(duì)齊問題。先看下面定義的兩個(gè)結(jié)構(gòu)體.struct{chara;shortb;charc;}S1;struct{chara;charb;s
2、hortc;}S2;分別用程序測(cè)試得出sizeof(S1)=6,sizeof(S2)=4可見,雖然兩個(gè)結(jié)構(gòu)體所含的元素相同,但因?yàn)槠渲写娣诺脑仡愋晚樞虿灰粯樱甲止?jié)也出現(xiàn)差異。這就是字節(jié)對(duì)齊原因。通過字節(jié)對(duì)齊,有助于加快計(jì)算機(jī)的取數(shù)速度,否則就得多花指令周期。字節(jié)對(duì)齊原則結(jié)構(gòu)體默認(rèn)的字節(jié)對(duì)齊一般滿足三個(gè)準(zhǔn)則:1)結(jié)構(gòu)體變量的首地址能夠被其最寬基本類型成員的大小所整除;2)結(jié)構(gòu)體每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的偏移量(offset,即每個(gè)成員的起始地址)都是成員自身大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上
3、填充字節(jié)(internaladding);3)結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)(trailingpadding)。注意:當(dāng)結(jié)構(gòu)體成員里面有數(shù)組成員時(shí),如inta[10],要看成10個(gè)整形變量才參與計(jì)算。通過這三個(gè)原則,就不難理解上面兩個(gè)struct的差異了.對(duì)于structS1,為了使short變量滿足字節(jié)對(duì)其準(zhǔn)則(2),即其存儲(chǔ)位置相對(duì)于結(jié)構(gòu)體首地址的offset是自身大小(short占2個(gè)字節(jié))的整數(shù)倍,必須在字節(jié)a后面填充一個(gè)字節(jié)以對(duì)齊
4、;再由準(zhǔn)則(3),為了滿足結(jié)構(gòu)體總大小為short大小的整數(shù)倍,必須再在c后面填充一個(gè)字節(jié)。對(duì)于structS2,卻不必如上所述的填充字節(jié),因?yàn)槠渲苯禹樞虼鎯?chǔ)已經(jīng)滿足了對(duì)齊準(zhǔn)則。如果將上面兩個(gè)結(jié)構(gòu)體中的short都改為int(占4個(gè)字節(jié)),那么會(huì)怎么樣呢?程序得出sizeof(S1)=12,sizeof(S2)=8利用上面的準(zhǔn)則,也不難計(jì)算得出這樣的結(jié)果。S1中在a后面填充3個(gè)字節(jié)、在c后面填充3個(gè)字節(jié),這樣一共12個(gè)字節(jié);S2中在a、b順序存儲(chǔ)之后填充兩個(gè)字節(jié)用以對(duì)其,這樣一共就8個(gè)字節(jié)。當(dāng)然,在某些時(shí)候
5、也可以設(shè)置字節(jié)對(duì)齊方式。這就需要使用#pragmapack。#pragmapack(push)//壓棧保存#pragmapack(1)//設(shè)置1字節(jié)對(duì)齊struct{chara;shortb;charc;}S1;#pragmapack(pop)//恢復(fù)先前設(shè)置如上所示,將對(duì)其方式設(shè)為1字節(jié)對(duì)齊,那么S1就不填充字節(jié),sizeof為各元素所占字節(jié)之和即4。這一點(diǎn)在從外部2進(jìn)制文件中讀入struct大小的數(shù)據(jù)到struct中,是很有用的.另外,還有如下的一種方式:·__attribute((aligned(n)
6、)),讓所作用的結(jié)構(gòu)成員對(duì)齊在n字節(jié)自然邊界上。如果結(jié)構(gòu)中有成員的長(zhǎng)度大于n,則按照最大成員的長(zhǎng)度來對(duì)齊?!_attribute__((packed)),取消結(jié)構(gòu)在編譯過程中的優(yōu)化對(duì)齊,按照實(shí)際占用字節(jié)數(shù)進(jìn)行對(duì)齊??战Y(jié)構(gòu)體structS3{};sizeof(S3);//結(jié)果為1“空結(jié)構(gòu)體”(不含數(shù)據(jù)成員)的大小不為0,而是1。試想一個(gè)“不占空間”的變量如何被取地址、兩個(gè)不同的“空結(jié)構(gòu)體”變量又如何得以區(qū)分呢于是,“空結(jié)構(gòu)體”變量也得被存儲(chǔ),這樣編譯器也就只能為其分配一個(gè)字節(jié)的空間用于占位了。有static
7、的結(jié)構(gòu)體structS4{chara;longb;staticlongc;//靜態(tài)};靜態(tài)變量存放在全局?jǐn)?shù)據(jù)區(qū)內(nèi),而sizeof計(jì)算棧中分配的空間的大小,故不計(jì)算在內(nèi),S4的大小為4+4=8。structS5{charc;inti;};structS6{???charc1;???S5s;???charc2};S5的最寬簡(jiǎn)單成員的類型為int,S6在考慮最寬簡(jiǎn)單類型成員時(shí)是將S5“打散”看的,所以S6的最寬簡(jiǎn)單類型為int,這樣,通過S6定義的變量,其存儲(chǔ)空間首地址需要被4整除,整個(gè)sizeof(S6)的值也
8、應(yīng)該被4整除。c1的偏移量為0,s的偏移量呢這時(shí)s是一個(gè)整體,它作為結(jié)構(gòu)體變量也滿足前面三個(gè)準(zhǔn)則,所以其大小為8,偏移量為4,c1與s之間便需要3個(gè)填充字節(jié),而c2與s之間就不需要了,所以c2的偏移量為12,算上c2的大小為13,13是不能被4整除的,這樣末尾還得補(bǔ)上3個(gè)填充字節(jié)。最后得到sizeof(S6)的值為16。