資源描述:
《c++字節(jié)對(duì)齊知識(shí)雜燴》由會(huì)員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在行業(yè)資料-天天文庫。
1、C++字節(jié)對(duì)齊知識(shí)雜燴1結(jié)構(gòu)體的sizeof1.1sizeof的定義先看一個(gè)結(jié)構(gòu)體:structS1{charc;inti;};sizeof(s1)在VC6中按默認(rèn)設(shè)置得到的結(jié)果為8。我們先看看sizeof的定義——sizeof的結(jié)果等于對(duì)象或者類型所占的內(nèi)存字節(jié)數(shù),好吧,那就讓我們來看看S1的內(nèi)存分配情況:S1s1={'a',0xFFFFFFFF};定義上面的變量后,加上斷點(diǎn),運(yùn)行程序,觀察s1所在的內(nèi)存,你發(fā)現(xiàn)了什么以我的VC6.0(sp6)為例,s1的地址為0x0012FF78,其數(shù)據(jù)內(nèi)容如下:0012FF78:61CCCCC
2、CFFFFFFFF發(fā)現(xiàn)了什么怎么中間夾雜了3個(gè)字節(jié)的CC看看MSDN上的說明:Whenappliedtoastructuretypeorvariable,sizeofreturnstheactualsize,whichmayincludepaddingbytesinsertedforalignment.原來如此,這就是傳說中的字節(jié)對(duì)齊啊!一個(gè)重要的話題出現(xiàn)了。為什么需要字節(jié)對(duì)齊計(jì)算機(jī)組成原理教導(dǎo)我們這樣有助于加快計(jì)算機(jī)的取數(shù)速度,否則就得多花指令周期了。為此,編譯器默認(rèn)會(huì)對(duì)結(jié)構(gòu)體進(jìn)行處理(實(shí)際上其它地方的數(shù)據(jù)變量也是如此),讓寬度為
3、2的基本數(shù)據(jù)類型(short等)都位于能被2整除的地址上,讓寬度為4的基本數(shù)據(jù)類型(int等)都位于能被4整除的地址上,以此類推。這樣,兩個(gè)數(shù)中間就可能需要加入填充字節(jié),所以整個(gè)結(jié)構(gòu)體的sizeof值就增長(zhǎng)了。讓我們交換一下S1中char與int的位置:structS2{inti;charc;};看看sizeof(S2)的結(jié)果為多少,怎么還是8再看看內(nèi)存,原來成員c后面仍然有3個(gè)填充字節(jié),這又是為什么啊別著急,下面總結(jié)規(guī)律。1.2sizeof準(zhǔn)則字節(jié)對(duì)齊的細(xì)節(jié)和編譯器實(shí)現(xiàn)相關(guān),但一般而言,滿足三個(gè)準(zhǔn)則:1)結(jié)構(gòu)體變量的首地址能夠被其
4、最寬基本類型成員的大小所整除;2)結(jié)構(gòu)體每個(gè)成員相對(duì)于結(jié)構(gòu)體首地址的偏移量(offset)都是成員大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上填充字節(jié)(internaladding);3)結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)(trailingpadding)。對(duì)于上面的準(zhǔn)則,有幾點(diǎn)需要說明:1)前面不是說結(jié)構(gòu)體成員的地址是其大小的整數(shù)倍,怎么又說到偏移量了呢因?yàn)橛辛说?點(diǎn)存在,所以我們就可以只考慮成員的偏移量,這樣思考起來簡(jiǎn)單。想想為什么。結(jié)構(gòu)體某個(gè)成員相對(duì)于結(jié)構(gòu)體首地址
5、的偏移量可以通過宏offsetof()來獲得,這個(gè)宏也在stddef.h中定義,如下:#defineoffsetof(s,m)(size_t)&(((s*)0)->m)解釋:(s*)0為申請(qǐng)一個(gè)s變量,從0位置為其分配內(nèi)存(安裝結(jié)構(gòu)的定義)。例如,想要獲得S2中c的偏移量,方法為size_tpos=offsetof(S2,c);//pos等于42)基本類型是指前面提到的像char、short、int、float、double這樣的內(nèi)置數(shù)據(jù)類型,這里所說的“數(shù)據(jù)寬度”就是指其sizeof的大小。由于結(jié)構(gòu)體的成員可以是復(fù)合類型,比如另外
6、一個(gè)結(jié)構(gòu)體,所以在尋找最寬基本類型成員時(shí),應(yīng)當(dāng)包括復(fù)合類型成員的子成員,而不是把復(fù)合成員看成是一個(gè)整體。但在確定復(fù)合類型成員的偏移位置時(shí)則是將復(fù)合類型作為整體看待。這里敘述起來有點(diǎn)拗口,思考起來也有點(diǎn)撓頭,還是讓我們看看例子吧(具體數(shù)值仍以VC6為例,以后不再說明):structS3{charc1;S1s;charc2};S1的最寬簡(jiǎn)單成員的類型為int,S3在考慮最寬簡(jiǎn)單類型成員時(shí)是將S1“打散”看的,所以S3的最寬簡(jiǎn)單類型為int,這樣,通過S3定義的變量,其存儲(chǔ)空間首地址需要被4整除,整個(gè)sizeof(S3)的值也應(yīng)該被4整除
7、。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(S3)的值為16。通過上面的敘述,我們可以得到一個(gè)公式:結(jié)構(gòu)體的大小等于最后一個(gè)成員的偏移量加上其大小再加上末尾的填充字節(jié)數(shù)目,即:sizeof(struct)=offsetof(lastitem)+sizeof(lastitem)+sizeof
8、(trailingpadding)1.1pack指令到這里,朋友們應(yīng)該對(duì)結(jié)構(gòu)體的sizeof有了一個(gè)全新的認(rèn)識(shí),但不要高興得太早,有一個(gè)影響sizeof的重要參量還未被提及,那便是編譯器的pack指令。它是用來調(diào)整結(jié)構(gòu)體對(duì)齊方式的,不