版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、30 May 2012 sizeof() 簡介關(guān)于內(nèi)存對齊:對于n字節(jié)的元素(n=2、4、8.), 它的首地址能被n整除才能獲得最好的性能! sizeof是運(yùn)算符,可用于任何變量名、類型名或常量值,當(dāng)用于變量名(不是數(shù)組名)或常量時(shí),它不需要用圓括號。 它在編譯時(shí)起作用,而不是運(yùn)行時(shí)。這是初學(xué)者問得最多的一個(gè)問題,所以這里有必要多費(fèi)點(diǎn)筆墨。讓我們先看一個(gè)結(jié)構(gòu)體:struct S1char c;int i;問sizeof(s1)等于多少聰明的你開始思考了,char占1個(gè)字節(jié),int占4個(gè)字節(jié),那么加起來就應(yīng)該是5。是這樣嗎你在你機(jī)器上試過了嗎也許你是對的,但很可能你是錯(cuò)的!VC6中按默認(rèn)設(shè)置得到
2、的結(jié)果為8。Why為什么受傷的總是我請不要沮喪,我們來好好琢磨一下sizeof的定義sizeof的結(jié)果等于對象或者類型所占的內(nèi)存字節(jié)數(shù),好吧,那就讓我們來看看S1的內(nèi)存分配情況:S1 s1 = 'a', 0xFFFFFFFF ;定義上面的變量后,加上斷點(diǎn),運(yùn)行程序,觀察s1所在的內(nèi)存,你發(fā)現(xiàn)了什么以我的VC6.0為例,s1的地址為0x0012FF78,其數(shù)據(jù)內(nèi)容如下:0012FF78: 61 CC CC CC FF FF FF FF發(fā)現(xiàn)了什么怎么中間夾雜了3個(gè)字節(jié)的CC看看MSDN上的說明:When applied to a structure type or variable
3、, sizeof returns the actual size, which may include padding bytes inserted for alignment.原來如此,這就是傳說中的字節(jié)對齊啊!一個(gè)重要的話題出現(xiàn)了。為什么需要字節(jié)對齊計(jì)算機(jī)組成原理教導(dǎo)我們這樣有助于加快計(jì)算機(jī)的取數(shù)速度,否則就得多花指令周期了。為此,編譯器默認(rèn)會對結(jié)構(gòu)體進(jìn)行處理(實(shí)際上其它地方的數(shù)據(jù)變量也是如此),讓寬度為2的基本數(shù)據(jù)類型(short等)都位于能被2整除的地址上,讓寬度為4的基本數(shù)據(jù)類型(int等)都位于能被 4整除的地址上,以此類推。這樣,兩個(gè)數(shù)中間就可能需要加入填充字節(jié),所以整個(gè)結(jié)構(gòu)體的
4、sizeof值就增長了。讓我們交換一下S1中char與int的位置:struct S2int i;char c;看看sizeof(S2)的結(jié)果為多少,怎么還是8再看看內(nèi)存,原來成員c后面仍然有3個(gè)填充字節(jié),這又是為什么啊別著急,下面總結(jié)規(guī)律。字節(jié)對齊的細(xì)節(jié)和編譯器實(shí)現(xiàn)相關(guān),但一般而言,滿足三個(gè)準(zhǔn)則:1) 結(jié)構(gòu)體變量的首地址能夠被其最寬基本類型成員的大小所整除;2) 結(jié)構(gòu)體每個(gè)成員相對于結(jié)構(gòu)體首地址的偏移量(offset)都是成員大小的整數(shù)倍,如有需要編譯器會在成員之間加上填充字節(jié)(internal adding);3) 結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要編譯器會在最末
5、一個(gè)成員之后加上填充字節(jié)(trailing padding)。1) 前面不是說結(jié)構(gòu)體成員的地址是其大小的整數(shù)倍,怎么又說到偏移量了呢因?yàn)橛辛说?點(diǎn)存在,所以我們就可以只考慮成員的偏移量,這樣思考起來簡單。想想為什么。結(jié)構(gòu)體某個(gè)成員相對于結(jié)構(gòu)體首地址的偏移量可以通過宏offsetof()來獲得,這個(gè)宏也在stddef.h中定義,如下:#define offsetof(s,m) (size_t)&(s *)0)->m)例如,想要獲得S2中c的偏移量,方法為size_t pos = offsetof(S2, c);/ pos等于42) 基本類型是指前面提到的像char、short、in
6、t、float、double這樣的內(nèi)置數(shù)據(jù)類型,這里所說的“數(shù)據(jù)寬度”就是指其sizeof的大小。由于結(jié)構(gòu)體的成員可以是復(fù)合類型,比如另外一個(gè)結(jié)構(gòu)體,所以在尋找最寬基本類型成員時(shí),應(yīng)當(dāng)包括復(fù)合類型成員的子成員,而不是把復(fù)合成員看成是一個(gè)整體。但在確定復(fù)合類型成員的偏移位置時(shí)則是將復(fù)合類型作為整體看待。這里敘述起來有點(diǎn)拗口,思考起來也有點(diǎn)撓頭,還是讓我們看看例子吧(具體數(shù)值仍以VC6為例,以后不再說明):struct S3char c1;S1 s;char c2;S1的最寬簡單成員的類型為int,S3在考慮最寬簡單類型成員時(shí)是將S1“打散”看的,所以S3的最寬簡單類型為int,這樣,通過S3定義
7、的變量,其存儲空間首地址需要被4整除,整個(gè)sizeof(S3)的值也應(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(S3)的值為16。通過上面的敘述,我們可以得到一個(gè)公式:結(jié)構(gòu)體的大小等于最后一個(gè)成員的偏移量加上其大小再加上末尾的填充字節(jié)數(shù)目,即:sizeof( struct ) = offsetof( last item ) + size
8、of( last item ) + sizeof( trailing padding )到這里,朋友們應(yīng)該對結(jié)構(gòu)體的sizeof有了一個(gè)全新的認(rèn)識,但不要高興得太早,有一個(gè)影響sizeof的重要參量還未被提及,那便是編譯器的 pack指令。它是用來調(diào)整結(jié)構(gòu)體對齊方式的,不同編譯器名稱和用法略有不同,VC6中通過#pragma pack實(shí)現(xiàn),也可以直接修改/Zp編譯開關(guān)。#pragma pack的基本用法為:#pragma pack( n ),n為字節(jié)對齊數(shù),其取值為1、2、4、8、16,默認(rèn)是8,如果這個(gè)值比結(jié)構(gòu)體成員的sizeof值小,那么該成員的偏移量應(yīng)該以此值為準(zhǔn),即是說,結(jié)構(gòu)體成員的偏
9、移量應(yīng)該取二者的最小值,公式如下:offsetof( item ) = min( n, sizeof( item ) )再看示例:#pragma pack(push) / 將當(dāng)前pack設(shè)置壓棧保存#pragma pack(2) / 必須在結(jié)構(gòu)體定義之前使用struct S1char c;int i;struct S3char c1;S1 s;char c2;#pragma pack(pop) / 恢復(fù)先前的pack設(shè)置計(jì)算sizeof(S1)時(shí),min(2, sizeof(i)的值為2,所以i的偏移量為2,加上sizeof(i)等于6,能夠被2整除,所以整個(gè)S1的大小為6。同樣,對于size
10、of(S3),s的偏移量為2,c2的偏移量為8,再加上sizeof(c2)=1結(jié)果為9,不能被2整除,添加一個(gè)填充字節(jié),所以sizeof(S3)等于10。現(xiàn)在,朋友們可以輕松的出一口氣了,:)還有一點(diǎn)要注意,“空結(jié)構(gòu)體”(不含數(shù)據(jù)成員)的大小不為0,而是1。試想一個(gè)“不占空間”的變量如何被取地址、兩個(gè)不同的“空結(jié)構(gòu)體”變量又如何得以區(qū)分呢于是,“空結(jié)構(gòu)體”變量也得被存儲,這樣編譯器也就只能為其分配一個(gè)字節(jié)的空間用于占位了。如下:struct S5 ;sizeof( S5 ); / 結(jié)果為1第一個(gè)例子: char* ss = "0123456789"sizeof(ss) 結(jié)果
11、 4 ss是指向字符串常量的字符指針sizeof(*ss) 結(jié)果 1 *ss是第一個(gè)字符char ss = "0123456789"sizeof(ss) 結(jié)果 11 ss是數(shù)組,計(jì)算到0位置,因此是101sizeof(*ss) 結(jié)果 1 *ss是第一個(gè)字符char ss100 = "0123456789"sizeof(ss) 結(jié)果是100 ss表示在內(nèi)存中的大小 100×1int ss100 = "0123456789"sizeof(ss) 結(jié)果 400 ss表示再內(nèi)存中的大小 100×4char q="
12、abc"char p="an"sizeof(q),sizeof(p),strlen(q),strlen(p);結(jié)果是 4 3 3 2第二個(gè)例子:class Xint i;int j;char k;X x;cout<<sizeof(X)<<endl; 結(jié)果 12 內(nèi)存補(bǔ)齊cout<<sizeof(x)<<endl; 結(jié)果 12 同上-sizeof()和strlen()區(qū)別:#include <iostream.h>#include <string>void main()char cha10=
13、39;a','b','c','d'cout<<"chasz:"<<cha<<endl;cout<<"strlen:"<<strlen(cha)<<endl;cha2='0'cout<<"sizeof:"<<sizeof(cha)<<endl;cout<<"strlen2:"<<strlen(cha)<<
14、endl;運(yùn)行結(jié)果:chasz:abcdstrlen:4sizeof:10strlen2:2Press any key to continue位域:補(bǔ)充:使用位域的主要目的是壓縮存儲,其大致規(guī)則為: 1) 如果相鄰位域字段的類型相同,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個(gè)字段存儲,直到不能容納為止; 2) 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數(shù)倍; 3) 如果相鄰的位域字段的類型不同,則各編譯器的具體實(shí)現(xiàn)有差異,VC6采取不壓縮方式,Dev-C+采取壓縮方式; 4) 如果位域字段
15、之間穿插著非位域字段,則不進(jìn)行壓縮; 5) 整個(gè)結(jié)構(gòu)體的總大小為最寬基本類型成員大小的整數(shù)倍。還是讓我們來看看例子。 示例1:struct BF1char f1 : 3;char f2 : 4;char f3 : 5;其內(nèi)存布局為: |_f1_|_f2_|_|_f3_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|0 3 7 8 1316位域類型為char,第1個(gè)字節(jié)僅能容納下f1和f2,所以f2被壓縮到第1個(gè)字節(jié)中,而f3只能從下一個(gè)字節(jié)開始。因此sizeof(BF1)的結(jié)果為2。 示例2:struct BF2char f1 : 3;short f2 : 4;char
16、f3 : 5;由于相鄰位域類型不同,在VC6中其sizeof為6,在Dev-C+中為2。 示例3:struct BF3char f1 : 3;char f2;char f3 : 5;非位域字段穿插在其中,不會產(chǎn)生壓縮,在VC6和Dev-C+中得到的大小均為3。9. 聯(lián)合體的sizeof結(jié)構(gòu)體在內(nèi)存組織上是順序式的,聯(lián)合體則是重疊式,各成員共享一段內(nèi)存,所以整個(gè)聯(lián)合體的sizeof也就是每個(gè)成員sizeof的最大值。結(jié)構(gòu)體的成員也可以是復(fù)合類型,這里,復(fù)合類型成員是被作為整體考慮的。所以,下面例子中,U的sizeof值等于sizeof(s)。union Uint i;char c;S1 s;1.
17、 數(shù)據(jù)類型自身的對齊值:對于char型數(shù)據(jù),其自身對齊值為1,對于short型為2,對于int,float類型,其自身對齊值為4,單位字節(jié)。2.結(jié)構(gòu)體或者類的自身對齊值:其成員中自身對齊值最大的那個(gè)值。3.指定對齊值:#pragma pack (value)時(shí)的指定對齊值value。4.數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對齊值:自身對齊值和指定對齊值中小的那個(gè)值。為什么要對齊?現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對任何類型的變量的訪問可以從任何地址開始,但實(shí)際情況是在訪問特定類型變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問,這就需要各種類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對齊。對齊的作用和原因:各個(gè)硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的 數(shù)據(jù)只能從某些特定地址開始存取。比如有些架構(gòu)的CPU在訪問一個(gè)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 玉溪師范學(xué)院《數(shù)據(jù)庫原理與應(yīng)用實(shí)訓(xùn)》2021-2022學(xué)年期末試卷
- 懷文第八章全章教案
- 作文寫作方法與思路
- 電動汽車 - 軸向磁通油冷電機(jī)
- 2024年速凍調(diào)理肉制品項(xiàng)目評估分析報(bào)告
- 2024年蓄熱式高溫預(yù)熱燒嘴項(xiàng)目成效分析報(bào)告
- 2024屆廣西壯族自治區(qū)欽州市高三假期自主綜合能力測試(三)數(shù)學(xué)試題
- 殘疾證個(gè)體工商戶合同
- 采購合同內(nèi)容匯報(bào)模板
- 不可抗拒原因員工解除合同協(xié)議書范本
- 師德師風(fēng)考試試卷及答案
- 全國教育科學(xué)規(guī)劃課題申報(bào)書:27.《教育數(shù)字化轉(zhuǎn)型的區(qū)域?qū)嵺`探索研究》
- 人教版九年級上冊化學(xué)期末考試試題帶答案
- 2024年村級防止返貧集中排查總結(jié)會議記錄
- 2024年復(fù)蘇中心建設(shè)與管理急診專家共識
- 部編版三年級上冊語文全冊教案(教案)
- 電信營業(yè)廳業(yè)務(wù)辦理指南預(yù)案
- 靜脈輸液治療護(hù)理技術(shù)操作規(guī)范
- 2023年12月英語四級真題及答案-第2套
- 2024天貓男裝行業(yè)秋冬趨勢白皮書
- 運(yùn)營內(nèi)控副行長/經(jīng)理資格認(rèn)證考試題庫(2021版)
評論
0/150
提交評論