日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

VC内存对齐准则(Memory alignment)

發(fā)布時間:2023/12/20 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VC内存对齐准则(Memory alignment) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

***************************************************

更多精彩,歡迎進入:http://shop115376623.taobao.com

***************************************************


本文所有內(nèi)容在建立在一個前提下:使用VC編譯器。著重點在于:VC的內(nèi)存對齊準則;同樣的數(shù)據(jù), 不同的排列有不同的大小,另外在有虛函數(shù)或虛擬繼承情況下又有如何影響?

內(nèi)存對齊?!What?Why?

對于一臺32位的機器來說如何才能發(fā)揮它的最佳存取效率呢?當(dāng)然是每次都讀4字節(jié)(32bit)(一個字節(jié)8位,一次讀取4個字節(jié),剛好滿負荷讀取), 這樣才可以讓它的bus處于最高效率。實際上它也是這么做的,即使你只需要一個字節(jié),它也是 讀一個機器字長(這兒是32bit)。更重要的是,有的機器在存取或存儲數(shù)據(jù)的時候它要求數(shù)據(jù) 必須是對齊的,何謂對齊?它要求數(shù)據(jù)的地址從4的倍數(shù)開始,如若不然,它就報錯。還有的機 器它雖然不報錯,但對于一個類似int變量,假如它橫跨一個邊界的兩端,那么它將要進行兩次 讀取才能獲得這個int值。比方它存儲在地址為2~5的四個字節(jié)中,那么要讀取這個int,將要 進行兩次讀取,第一次讀取0~3四個字節(jié),第二次讀取4~7四個字節(jié)。但是如果我們把這個整 形的起始地址調(diào)整到0,4,8…呢?一次存取就夠了!這種調(diào)整就是內(nèi)存對齊了。我們也可以依次 類推到16位或64位的機器上。

邊界該如何調(diào)整

對于32位的機器來說,它當(dāng)然最渴望它的數(shù)據(jù)的大小都是4 Byte或者4的倍數(shù)Byte,這樣它就能 最有效率的存取數(shù)據(jù),當(dāng)然如果數(shù)據(jù)小于4Byte,那也是沒問題的。那么編譯器要做的便是盡量滿 足這個要求。

這兩天我斷續(xù)對VC做了一些實驗,并總結(jié)如下三條準則,你要明白的是這并非來自微軟的官方文 檔,但我自以為這些準則或許不全但應(yīng)該都是正確的:

  • 變量存放的起始位置2應(yīng)為變量的大小與規(guī)定對齊量1中較小者的倍數(shù)。例如,假 設(shè)規(guī)定對齊量為4,那么char(1byte)變量應(yīng)該存儲在偏移量為1的倍數(shù)的地方,而整形變 量(4byte)則是從偏移量為4的倍數(shù)的地方,而double(8 byte)也同樣應(yīng)存儲在偏移量為 4的倍數(shù)的地方,為什么不是8?因為規(guī)定對齊量默認值為4,而4 < 8。在VC中默認對齊量 為8,而非4
  • 結(jié)構(gòu)體整體的大小也應(yīng)該對齊,對齊依照規(guī)定對齊量與最大數(shù)據(jù)成員兩者中較小的進行。
  • Vptr影響對齊而VbcPoint(Virtual base class pointer)不影響。

一個實例

對于類T:

class T{char c;int i;double d;};

將其sizeof輸出后的大小為16,其內(nèi)存布局如圖T.變量c從偏移量為0開始存儲,而整形i第一個 符號條件的偏移量為4,double型d的第一個符號條件的為8。整個對象的大小為16,不需要再進 行額外的對齊。

圖T(類T 的內(nèi)存布局) :

同樣的數(shù)據(jù),不同的大小

再看類L,它與T存儲同樣類型的數(shù)據(jù),僅僅是順序不同罷了,那么它sizeof輸出的大小是多少呢?

類L:

class L{char c;double d;int i;};

它sizeof后的結(jié)果或許會令你大吃一驚,或許不會(如果你有認真讀前面的兩條準則)。L sizeof后的結(jié)果是24!同樣是一個int,一個char,一個double卻整整多出了8個字節(jié)。這期間 發(fā)生了什么?我們依據(jù)前面兩條規(guī)則來看看。C存儲于0的位置,1~7都不能整除8,所以d存儲 在8~15,16給i正好合適,i存儲在16~19。總共花費了20個字節(jié),抱歉不是8的倍數(shù),還得補 齊4個。現(xiàn)在你可以看看圖L的關(guān)于類L的內(nèi)存布局,再比較一下類L和類T的內(nèi)存布局。

圖L(類L的布局)

我得出了這樣一條并不權(quán)威的結(jié)論,因為我還沒聽有人這樣說過:在聲明數(shù)據(jù)成員的時候,將 最大字節(jié)數(shù)的變量放在最前面3,切忌不要將大小差距很大的類型交替聲明。

Vptr影響對齊而VbcPoint(Virtual base class pointer)不影響

前面的實例只涉及前兩條準則,現(xiàn)在我們來看看第三條的兩個實例:

class X{char a;}; class Y: virtual public X{};

Y的大小為:a占一個字節(jié),VbcPoint(我稱他為虛基類指針)占四個字節(jié)。我們不論a與VbcPoint 的位置如何擺放,如果將VbcPoint等同于一個成員數(shù)據(jù)來看的話,sizeof(Y)都應(yīng)該為8.實際上 它是5!就我目前的水平,我只能先將其解釋為VbcPoint不參與對齊。

對于vptr這個問題則不存在:

class X{char a;virtual int vfc(){};}

sizeof(X)的大小確實為8.

關(guān)于#pragma pack(n)

用#pragma pack(n)改變規(guī)定對齊量試試。


  • 規(guī)定對齊量:實際上并沒有這么一個名詞,是我為了方便而造出來的。在VC中這個“規(guī)定對齊量”會有一個默認值,這個默認值一般為8,我原來一直以為這個值以為是4,至于它為什么為8,我現(xiàn)在還不知道。。我們也可以通過#pargma pack(n)來規(guī)定這個值,目前n可以為1,2,4,8,16。??

  • 這個起始位置指的是相對于結(jié)構(gòu)體(類)來說的。??

  • 此處有一點問題,這個問題由獨酌逸醉提出,他認為將最小的數(shù)據(jù)放在最前面可能會更好,我們有進行過討論,但可惜的是由于在2011/11/24日數(shù)據(jù)庫丟失,我只能用備份還原,所以丟失了一些數(shù)據(jù),無疑,本文的評論也在其中。不過我對這個問題映像深刻,因為我在寫這篇博客的時候便困惑于到底成員是應(yīng)該放在之前還是之后,因為這兩種情況我都找不到強有力的理由來支撐它們。后來使我確信從大到小排列好于從小到大排列的理由在于,從大到小排列一般無需成員之間的對齊,唯一的對齊工作是最后進行的整個結(jié)構(gòu)體對齊的工作。毫無疑問的是,這應(yīng)該是最節(jié)省內(nèi)存的方式。再之后,獨酌提出從小到大可能好些,雖然沒有給出有說服力的理由,但卻使我無比困惑,我當(dāng)時雖然認為從大到小的排列更有優(yōu)勢,但卻實在想不出一個實例能使得它優(yōu)于從小到大排列的。不過最終我擊垮了自己的理由,在繼承狀況下從大到小排列很容易被打破,比方,基類的成員為一個char,繼承類的成員為double,int,char雖然基類和繼承類都是按從大到小的順序排列的,但是繼承類的內(nèi)存布局最終會使char,double,int,char,此時既不能避免成員對齊,又導(dǎo)致后面的結(jié)構(gòu)體對齊。暫時獲得的最終結(jié)果是從小到大排列是更好的一種排列方式。(2011/12/31增補)?

  • 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的VC内存对齐准则(Memory alignment)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。