




免費預(yù)覽已結(jié)束,剩余7頁可下載查看
下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
對齊原則為:單字節(jié)變量無需對齊,可放在任何地址雙字節(jié)變量起始地址為2的倍數(shù)4字節(jié)變量首地址為4的倍數(shù)一個結(jié)構(gòu)體變量定義完之后,其在內(nèi)存中的存儲并不等于其所包含元素的寬度之和。例一:#include using namespace std; structX char a; int b;double c;S1;void main() cout sizeof(S1) endl; cout sizeof(S1.a) endl; cout sizeof(S1.b) endl; cout sizeof(S1.c) endl; 比如例一中的結(jié)構(gòu)體變量S1定義之后,經(jīng)測試,會發(fā)現(xiàn)sizeof(S1)= 16,其值不等于sizeof(S1.a) = 1、sizeof(S1.b) = 4和 sizeof(S1.c) = 8三者之和,這里面就存在存儲對齊問題。原則一:結(jié)構(gòu)體中元素是按照定義順序一個一個放到內(nèi)存中去的,但并不是緊密排列的。從結(jié)構(gòu)體存儲的首地址開始,每一個元素放置到內(nèi)存中時,它都會認為內(nèi)存是以它自己的大小來劃分的,因此元素放置的位置一定會在自己寬度的整數(shù)倍上開始(以結(jié)構(gòu)體變量首地址為0計算)。 比如此例,首先系統(tǒng)會將字符型變量a存入第0個字節(jié)(相對地址,指內(nèi)存開辟的首地址);然后在存放整形變量b時,會以4個字節(jié)為單位進行存儲,由于第一個四字節(jié)模塊已有數(shù)據(jù),因此它會存入第二個四字節(jié)模塊,也就是存入到48字節(jié);同理,存放雙精度實型變量c時,由于其寬度為8,其存放時會以8個字節(jié)為單位存儲,也就是會找到第一個空的且是8的整數(shù)倍的位置開始存儲,此例中,此例中,由于頭一個8字節(jié)模塊已被占用,所以將c存入第二個8字節(jié)模塊。整體存儲示意圖如圖1所示。 考慮另外一個實例。例二: struct X char a; double b; int c;S2; 在例二中僅僅是將double型的變量和int型的變量互換了位置。測試程序不變,測試結(jié)果卻截然不同,sizeof(S2)=24,不同于我們按照原則一計算出的8+8+4=20,這就引出了我們的第二原則。 原則二:在經(jīng)過第一原則分析后,檢查計算出的存儲單元是否為所有元素中最寬的元素的長度的整數(shù)倍,是,則結(jié)束;若不是,則補齊為它的整數(shù)倍。 例二中,我們分析完后的存儲長度為20字節(jié),不是最寬元素長度8的整數(shù)倍,因此將它補齊到8的整數(shù)倍,也就是24。這樣就沒問題了。其存儲示意圖如圖2所示。 掌握了這兩個原則,就能夠分析所有數(shù)據(jù)存儲對齊問題了。再來看幾個例子,應(yīng)用以上兩個原則來判斷。例三: struct X double a;char b;int c; S3; 首先根據(jù)原則一來分析。按照定義的順序,先存儲double型的a,存儲在第07個字節(jié);其次是char型的b,存儲在第8個字節(jié);接下來是int型的c,順序檢查后發(fā)現(xiàn)前面三個四字節(jié)模塊都被占用,因此存儲在第4個四字節(jié)模塊,也就是第1215字節(jié)。按照第一原則分析得到16個字節(jié),16正好是最寬元素a的寬度8的整數(shù)倍,因此結(jié)構(gòu)體變量S3所占存儲空間就是16個字節(jié)。存儲結(jié)構(gòu)如圖3所示。例四: struct X double a; char b;int c;char d; S4; 仍然首先按照第一原則分析,得到的字節(jié)數(shù)為8+4+4+1=17;再按照第二原則補齊,則結(jié)構(gòu)體變量S4所占存儲空間為24。存儲結(jié)構(gòu)如圖4所示:例五: struct X double a; char b; int c; char d; int e; S5; 同樣結(jié)合原則一和原則二分析,可知在S4的基礎(chǔ)上在結(jié)構(gòu)體內(nèi)部變量定義最后加入一個int型變量后,結(jié)構(gòu)體所占空間并未增加,仍為24。存儲結(jié)構(gòu)示意圖如圖5所示。例六: 如果將例五中加入的變量e放到第一個定義的位置,則情況就不同了。結(jié)構(gòu)體所占存儲空間會變?yōu)?2。其存儲結(jié)構(gòu)示意圖如圖6所示。 struct X int e; double a;char b; int c;char d; S6;補充:前面所介紹的都是元素為基本數(shù)據(jù)類型的結(jié)構(gòu)體,那么含有指針、數(shù)組或是其它結(jié)構(gòu)體變量或聯(lián)合體變量時該如何呢? 1.包含指針類型的情況。只要記住指針本身所占的存儲空間是4個字節(jié)就行了,而不必看它是指向什么類型的指針。例七:struct X struct Y struct Zchar *a; int *b;double *c; ; 經(jīng)測試,可知sizeof(X)、sizeof(Y)和sizeof(Z)的值都為4。2.含有構(gòu)造數(shù)據(jù)類型(數(shù)組、結(jié)構(gòu)體和聯(lián)合體)的情況。首先要明確的是計算存儲空間時要把構(gòu)造體看作一個整體來為其開辟存儲空間;其次要明確的是在最后補齊時是按照所有元素中的基本數(shù)據(jù)類型元素的最長寬度來補齊的,也就是說雖然要把構(gòu)造體看作整體,但在補齊的時候并不會按照所含結(jié)構(gòu)體所占存儲空間的長度來補齊的(即使它可能是最長的)。例八: struct Xchar a;int b; double c; ; struct Y char a;X b; ; 經(jīng)測試,可知sizeof(X)為16,sizeof(Y)為24。即計算Y的存儲長度時,在存放第二個元素b時的初始位置是在double型的長度8的整數(shù)倍處,而非16的整數(shù)倍處,即系統(tǒng)為b所分配的存儲空間是第823個字節(jié)。如果將Y的兩個元素char型的a和X型的b調(diào)換定義順序,則系統(tǒng)為b分配的存儲位置是第015個字節(jié),為a分配的是第16個字節(jié),加起來一共17個字節(jié),不是最長基本類型double所占寬度8的整數(shù)倍,因此要補齊到8的整數(shù)倍,即24。測試后可得sizeof(Y)的值為24。由于結(jié)構(gòu)體所占空間與其內(nèi)部元素的類型有關(guān),而且與不同類型元素的排列有關(guān),因此在定義結(jié)構(gòu)體時,在元素類型及數(shù)量確定之后,我們還應(yīng)該注意一下其內(nèi)部元素的定義順序。二.編譯器是按照什么樣的原則進行對齊的? 先讓我們看四個重要的基本概念:1.數(shù)據(jù)類型自身的對齊值: 對于char型數(shù)據(jù),其自身對齊值為1,對于short型為2,對于int,float,double類型,其自身對齊值為4,單位字節(jié)。2.結(jié)構(gòu)體或者類的自身對齊值:其成員中自身對齊值最大的那個值。3.指定對齊值:#pragma pack (value)時的指定對齊值value。4.數(shù)據(jù)成員、結(jié)構(gòu)體和類的有效對齊值:自身對齊值和指定對齊值中小的那個值。有 了這些值,我們就可以很方便的來討論具體數(shù)據(jù)結(jié)構(gòu)的成員和其自身的對齊方式。有效對齊值N是最終用來決定數(shù)據(jù)存放地址方式的值,最重要。有效對齊N,就是 表示“對齊在N上”,也就是說該數(shù)據(jù)的存放起始地址%N=0.而數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)變量都是按定義的先后順序來排放的。第一個數(shù)據(jù)變量的起始地址就是數(shù) 據(jù)結(jié)構(gòu)的起始地址。結(jié)構(gòu)體的成員變量要對齊排放,結(jié)構(gòu)體本身也要根據(jù)自身的有效對齊值圓整(就是結(jié)構(gòu)體成員變量占用總長度需要是對結(jié)構(gòu)體有效對齊值的整數(shù) 倍,結(jié)合下面例子理解)。這樣就不能理解上面的幾個例子的值了。例子分析:分析例子B;struct B char b; int a; short c;假 設(shè)B從地址空間0x0000開始排放。該例子中沒有定義指定對齊值,在筆者環(huán)境下,該值默認為4。第一個成員變量b的自身對齊值是1,比指定或者默認指定 對齊值4小,所以其有效對齊值為1,所以其存放地址0x0000符合0x0000%1=0.第二個成員變量a,其自身對齊值為4,所以有效對齊值也為4, 所以只能存放在起始地址為0x0004到0x0007這四個連續(xù)的字節(jié)空間中,復(fù)核0x0004%4=0,且緊靠第一個變量。第三個變量c,自身對齊值為 2,所以有效對齊值也是2,可以存放在0x0008到0x0009這兩個字節(jié)空間中,符合0x0008%2=0。所以從0x0000到0x0009存放的 都是B內(nèi)容。再看數(shù)據(jù)結(jié)構(gòu)B的自身對齊值為其變量中最大對齊值(這里是b)所以就是4,所以結(jié)構(gòu)體的有效對齊值也是4。根據(jù)結(jié)構(gòu)體圓整的要求, 0x0009到0x0000=10字節(jié),(102)40。所以0x0000A到0x000B也為結(jié)構(gòu)體B所占用。故B從0x0000到0x000B 共有12個字節(jié),sizeof(struct B)=12;其實如果就這一個就來說它已將滿足字節(jié)對齊了, 因為它的起始地址是0,因此肯定是對齊的,之所以在后面補充2個字節(jié),是因為編譯器為了實現(xiàn)結(jié)構(gòu)數(shù)組的存取效率,試想如果我們定義了一個結(jié)構(gòu)B的數(shù)組,那 么第一個結(jié)構(gòu)起始地址是0沒有問題,但是第二個結(jié)構(gòu)呢?按照數(shù)組的定義,數(shù)組中所有元素都是緊挨著的,如果我們不把結(jié)構(gòu)的大小補充為4的整數(shù)倍,那么下一 個結(jié)構(gòu)的起始地址將是0x0000A,這顯然不能滿足結(jié)構(gòu)的地址對齊了,因此我們要把結(jié)構(gòu)補充成有效對齊大小的整數(shù)倍.其實諸如:對于char型數(shù)據(jù),其 自身對齊值為1,對于short型為2,對于int,float類型,其自身對齊值為4,,double自身對齊值為8,這些已有類型的自身對齊值也是基于數(shù)組考慮的,只 是因為這些類型的長度已知了,所以他們的自身對齊值也就已知了.同理,分析上面例子C:#pragma pack (2) /*指定按2字節(jié)對齊*/struct C char b; int a; short c;#pragma pack () /*取消指定對齊,恢復(fù)缺省對齊*/第 一個變量b的自身對齊值為1,指定對齊值為2,所以,其有效對齊值為1,假設(shè)C從0x0000開始,那么b存放在0x0000,符合0x0000%1= 0;第二個變量,自身對齊值為4,指定對齊值為2,所以有效對齊值為2,所以順序存放在0x0002、0x0003、0x0004、0x0005四個連續(xù) 字節(jié)中,符合0x0002%2=0。第三個變量c的自身對齊值為2,所以有效對齊值為2,順序存放在0x0006、0x0007中,符合 0x0006%2=0。所以從0x0000到0x00007共八字節(jié)存放的是C的變量。又C的自身對齊值為4,所以C的有效對齊值為2。又8%2=0,C 只占用0x0000到0x0007的八個字節(jié)。所以sizeof(struct C)=8.三.如何修改編譯器的默認對齊值?1.在VC IDE中,可以這樣修改:Project|Settings,c/c+選項卡Category的Code Generation選項的Struct Member Alignment中修改,默認是8字節(jié)。2.在編碼時,可以這樣動態(tài)修改:#pragma pack .通常,我們在定義結(jié)構(gòu)體的時候,不會管編譯器是怎樣的對齊方式,但在特定的場合,需要結(jié)構(gòu)體占用內(nèi)存數(shù)正好為內(nèi)成員定義時的類型所占字節(jié)數(shù)之和。例如:struct testint a;char b;int c;在編譯時,編譯器會按照默認對齊方式進行空間分配,在使用sizeof運算符得到的大小為12字節(jié),但我們本意是按照9個字節(jié)的內(nèi)存進行分配。有以下幾種方式:1.#pragma pack (n) /將結(jié)構(gòu)體中的成員按n字節(jié)對齊struct testint a;char b;int c;#pragma pack () /取消自定義字節(jié)方式2.#pragma pack (push, 1) /將原來的對齊方式入棧,設(shè)置新的對齊方式為1字節(jié)struct
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 茂名職業(yè)技術(shù)學(xué)院《社會工作法規(guī)與政策》2023-2024學(xué)年第二學(xué)期期末試卷
- 銅仁學(xué)院《研學(xué)旅行培訓(xùn)》2023-2024學(xué)年第二學(xué)期期末試卷
- 成都藝術(shù)職業(yè)大學(xué)《云計算平臺技術(shù)》2023-2024學(xué)年第二學(xué)期期末試卷
- 浙江廣廈建設(shè)職業(yè)技術(shù)大學(xué)《魏碑臨摹》2023-2024學(xué)年第二學(xué)期期末試卷
- 燕京理工學(xué)院《教學(xué)理論與實踐》2023-2024學(xué)年第二學(xué)期期末試卷
- 西安城市建設(shè)職業(yè)學(xué)院《酒類生產(chǎn)工藝與產(chǎn)品質(zhì)量控制》2023-2024學(xué)年第二學(xué)期期末試卷
- 廣西工業(yè)職業(yè)技術(shù)學(xué)院《男生羽毛球》2023-2024學(xué)年第二學(xué)期期末試卷
- 大學(xué)生就業(yè)指導(dǎo)考核復(fù)習(xí)題庫58題含答案
- 江蘇財經(jīng)職業(yè)技術(shù)學(xué)院《地方公共政策學(xué)》2023-2024學(xué)年第二學(xué)期期末試卷
- 商洛職業(yè)技術(shù)學(xué)院《面向?qū)ο驝程序設(shè)計1》2023-2024學(xué)年第二學(xué)期期末試卷
- 【生物】蒸騰作用- 2024-2025學(xué)年七年級上冊生物(北師大版2024)
- 摩根大通金融科技支出
- 《井巷掘進作業(yè)》課件
- 提高鋁合金外窗防滲漏施工一次合格率
- 銀行保安服務(wù) 投標方案(技術(shù)方案)
- 《TCPIP協(xié)議基礎(chǔ)》課件
- 農(nóng)村砍樹賠償合同模板
- 2024年貴州省公務(wù)員錄用考試《行測》真題及答案解析
- 工程造價基礎(chǔ)知識課件
- 2024年相機租賃合同書范本
- Python快速編程入門(第2版)完整全套教學(xué)課件
評論
0/150
提交評論