青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

saga's blog

突出重點(diǎn),系統(tǒng)全面,不留死角

  C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
  33 Posts :: 2 Stories :: 185 Comments :: 0 Trackbacks

公告

QQ:34O859O5

常用鏈接

留言簿(15)

搜索

  •  

積分與排名

  • 積分 - 212563
  • 排名 - 124

最新評論

閱讀排行榜

評論排行榜

選擇自 soloist 的 Blog 作者:不詳? 如原作者發(fā)現(xiàn)并不允許轉(zhuǎn)載請通知我,我會刪除!


當(dāng)在C中定義了一個結(jié)構(gòu)類型時(shí),它的大小是否等于各字段(field)大小之和?編譯器將如何在內(nèi)存中放置這些字段?ANSI C對結(jié)構(gòu)體的內(nèi)存布局有什么要求?而我們的程序又能否依賴這種布局?這些問題或許對不少朋友來說還有點(diǎn)模糊,那么本文就試著探究它們背后的秘密。

??? 首先,至少有一點(diǎn)可以肯定,那就是ANSI C保證結(jié)構(gòu)體中各字段在內(nèi)存中出現(xiàn)的位置是隨它們的聲明順序依次遞增的,并且第一個字段的首地址等于整個結(jié)構(gòu)體實(shí)例的首地址。比如有這樣一個結(jié)構(gòu)體:
?
? struct vector{int x,y,z;} s;
? int *p,*q,*r;
? struct vector *ps;
?
? p = &s.x;
? q = &s.y;
? r = &s.z;
? ps = &s;

? assert(p < q);
? assert(p < r);
? assert(q < r);
? assert((int*)ps == p);
? // 上述斷言一定不會失敗

??? 這時(shí),有朋友可能會問:"標(biāo)準(zhǔn)是否規(guī)定相鄰字段在內(nèi)存中也相鄰?"。 唔,對不起,ANSI C沒有做出保證,你的程序在任何時(shí)候都不應(yīng)該依賴這個假設(shè)。那這是否意味著我們永遠(yuǎn)無法勾勒出一幅更清晰更精確的結(jié)構(gòu)體內(nèi)存布局圖?哦,當(dāng)然不是。不過先讓我們從這個問題中暫時(shí)抽身,關(guān)注一下另一個重要問題————內(nèi)存對齊。

??? 許多實(shí)際的計(jì)算機(jī)系統(tǒng)對基本類型數(shù)據(jù)在內(nèi)存中存放的位置有限制,它們會要求這些數(shù)據(jù)的首地址的值是某個數(shù)k(通常它為4或8)的倍數(shù),這就是所謂的內(nèi)存對齊,而這個k則被稱為該數(shù)據(jù)類型的對齊模數(shù)(alignment modulus)。當(dāng)一種類型S的對齊模數(shù)與另一種類型T的對齊模數(shù)的比值是大于1的整數(shù),我們就稱類型S的對齊要求比T強(qiáng)(嚴(yán)格),而稱T比S弱(寬松)。這種強(qiáng)制的要求一來簡化了處理器與內(nèi)存之間傳輸系統(tǒng)的設(shè)計(jì),二來可以提升讀取數(shù)據(jù)的速度。比如這么一種處理器,它每次讀寫內(nèi)存的時(shí)候都從某個8倍數(shù)的地址開始,一次讀出或?qū)懭?個字節(jié)的數(shù)據(jù),假如軟件能保證double類型的數(shù)據(jù)都從8倍數(shù)地址開始,那么讀或?qū)懸粋€double類型數(shù)據(jù)就只需要一次內(nèi)存操作。否則,我們就可能需要兩次內(nèi)存操作才能完成這個動作,因?yàn)閿?shù)據(jù)或許恰好橫跨在兩個符合對齊要求的8字節(jié)內(nèi)存塊上。某些處理器在數(shù)據(jù)不滿足對齊要求的情況下可能會出錯,但是Intel的IA32架構(gòu)的處理器則不管數(shù)據(jù)是否對齊都能正確工作。不過Intel奉勸大家,如果想提升性能,那么所有的程序數(shù)據(jù)都應(yīng)該盡可能地對齊。Win32平臺下的微軟C編譯器(cl.exe for 80x86)在默認(rèn)情況下采用如下的對齊規(guī)則: 任何基本數(shù)據(jù)類型T的對齊模數(shù)就是T的大小,即sizeof(T)。比如對于double類型(8字節(jié)),就要求該類型數(shù)據(jù)的地址總是8的倍數(shù),而char類型數(shù)據(jù)(1字節(jié))則可以從任何一個地址開始。Linux下的GCC奉行的是另外一套規(guī)則(在資料中查得,并未驗(yàn)證,如錯誤請指正):任何2字節(jié)大小(包括單字節(jié)嗎?)的數(shù)據(jù)類型(比如short)的對齊模數(shù)是2,而其它所有超過2字節(jié)的數(shù)據(jù)類型(比如long,double)都以4為對齊模數(shù)。

??? 現(xiàn)在回到我們關(guān)心的struct上來。ANSI C規(guī)定一種結(jié)構(gòu)類型的大小是它所有字段的大小以及字段之間或字段尾部的填充區(qū)大小之和。嗯?填充區(qū)?對,這就是為了使結(jié)構(gòu)體字段滿足內(nèi)存對齊要求而額外分配給結(jié)構(gòu)體的空間。那么結(jié)構(gòu)體本身有什么對齊要求嗎?有的,ANSI C標(biāo)準(zhǔn)規(guī)定結(jié)構(gòu)體類型的對齊要求不能比它所有字段中要求最嚴(yán)格的那個寬松,可以更嚴(yán)格(但此非強(qiáng)制要求,VC7.1就僅僅是讓它們一樣嚴(yán)格)。我們來看一個例子(以下所有試驗(yàn)的環(huán)境是Intel Celeron 2.4G + WIN2000 PRO + vc7.1,內(nèi)存對齊編譯選項(xiàng)是"默認(rèn)",即不指定/Zp與/pack選項(xiàng)):

? typedef struct ms1
? {
???? char a;
???? int b;
? } MS1;

??? 假設(shè)MS1按如下方式內(nèi)存布局(本文所有示意圖中的內(nèi)存地址從左至右遞增):
?????? _____________________________
?????? |?????? |?????????????????? |
?????? |?? a?? |??????? b????????? |
?????? |?????? |?????????????????? |
?????? +---------------------------+
?Bytes:??? 1???????????? 4

??? 因?yàn)镸S1中有最強(qiáng)對齊要求的是b字段(int),所以根據(jù)編譯器的對齊規(guī)則以及ANSI C標(biāo)準(zhǔn),MS1對象的首地址一定是4(int類型的對齊模數(shù))的倍數(shù)。那么上述內(nèi)存布局中的b字段能滿足int類型的對齊要求嗎?嗯,當(dāng)然不能。如果你是編譯器,你會如何巧妙安排來滿足CPU的癖好呢?呵呵,經(jīng)過1毫秒的艱苦思考,你一定得出了如下的方案:

?????? _______________________________________
?????? |?????? |\\\\\\\\\\\|???????????????? |
?????? |?? a?? |\\padding\\|?????? b???????? |
?????? |?????? |\\\\\\\\\\\|???????????????? |
?????? +-------------------------------------+
?Bytes:??? 1???????? 3???????????? 4

??? 這個方案在a與b之間多分配了3個填充(padding)字節(jié),這樣當(dāng)整個struct對象首地址滿足4字節(jié)的對齊要求時(shí),b字段也一定能滿足int型的4字節(jié)對齊規(guī)定。那么sizeof(MS1)顯然就應(yīng)該是8,而b字段相對于結(jié)構(gòu)體首地址的偏移就是4。非常好理解,對嗎?現(xiàn)在我們把MS1中的字段交換一下順序:

? typedef struct ms2
? {
???? int a;
???? char b;
? } MS2;

??? 或許你認(rèn)為MS2比MS1的情況要簡單,它的布局應(yīng)該就是

?????? _______________________
?????? |???????????? |?????? |
?????? |???? a?????? |?? b?? |
?????? |???????????? |?????? |
?????? +---------------------+
?Bytes:????? 4?????????? 1

??? 因?yàn)镸S2對象同樣要滿足4字節(jié)對齊規(guī)定,而此時(shí)a的地址與結(jié)構(gòu)體的首地址相等,所以它一定也是4字節(jié)對齊。嗯,分析得有道理,可是卻不全面。讓我們來考慮一下定義一個MS2類型的數(shù)組會出現(xiàn)什么問題。C標(biāo)準(zhǔn)保證,任何類型(包括自定義結(jié)構(gòu)類型)的數(shù)組所占空間的大小一定等于一個單獨(dú)的該類型數(shù)據(jù)的大小乘以數(shù)組元素的個數(shù)。換句話說,數(shù)組各元素之間不會有空隙。按照上面的方案,一個MS2數(shù)組array的布局就是:

|<-??? array[1]???? ->|<-??? array[2]???? ->|<-?array[3] .....

__________________________________________________________
|???????????? |?????? |????????????? |????? |
|???? a?????? |?? b?? |????? a?????? |?? b? |.............
|???????????? |?????? |????????????? |????? |
+----------------------------------------------------------
Bytes:? 4???????? 1????????? 4?????????? 1

??? 當(dāng)數(shù)組首地址是4字節(jié)對齊時(shí),array[1].a也是4字節(jié)對齊,可是array[2].a呢?array[3].a ....呢?可見這種方案在定義結(jié)構(gòu)體數(shù)組時(shí)無法讓數(shù)組中所有元素的字段都滿足對齊規(guī)定,必須修改成如下形式:

?????? ___________________________________
?????? |???????????? |?????? |\\\\\\\\\\\|
?????? |???? a?????? |?? b?? |\\padding\\|
?????? |???????????? |?????? |\\\\\\\\\\\|
?????? +---------------------------------+
?Bytes:????? 4?????????? 1???????? 3

??? 現(xiàn)在無論是定義一個單獨(dú)的MS2變量還是MS2數(shù)組,均能保證所有元素的所有字段都滿足對齊規(guī)定。那么sizeof(MS2)仍然是8,而a的偏移為0,b的偏移是4。

??? 好的,現(xiàn)在你已經(jīng)掌握了結(jié)構(gòu)體內(nèi)存布局的基本準(zhǔn)則,嘗試分析一個稍微復(fù)雜點(diǎn)的類型吧。

? typedef struct ms3
? {
???? char a;
???? short b;
???? double c;
? } MS3;

??? 我想你一定能得出如下正確的布局圖:
????????
??????? padding?
?????????? |
????? _____v_________________________________
????? |?? |\|???? |\\\\\\\\\|?????????????? |
????? | a |\|? b? |\padding\|?????? c?????? |
????? |?? |\|???? |\\\\\\\\\|?????????????? |
????? +-------------------------------------+
Bytes:? 1? 1?? 2?????? 4??????????? 8
??????????
??? sizeof(short)等于2,b字段應(yīng)從偶數(shù)地址開始,所以a的后面填充一個字節(jié),而sizeof(double)等于8,c
字段要從8倍數(shù)地址開始,前面的a、b字段加上填充字節(jié)已經(jīng)有4 bytes,所以b后面再填充4個字節(jié)就可以保證c字段的對齊要求了。sizeof(MS3)等于16,b的偏移是2,c的偏移是8。接著看看結(jié)構(gòu)體中字段還是結(jié)構(gòu)類型的情況:

? typedef struct ms4
? {
???? char a;
???? MS3 b;
? } MS4;

??? MS3中內(nèi)存要求最嚴(yán)格的字段是c,那么MS3類型數(shù)據(jù)的對齊模數(shù)就與double的一致(為8),a字段后面應(yīng)填充7個字節(jié),因此MS4的布局應(yīng)該是:
?????? _______________________________________
?????? |?????? |\\\\\\\\\\\|???????????????? |
?????? |?? a?? |\\padding\\|?????? b???????? |
?????? |?????? |\\\\\\\\\\\|???????????????? |
?????? +-------------------------------------+
?Bytes:??? 1???????? 7???????????? 16

??? 顯然,sizeof(MS4)等于24,b的偏移等于8。

??? 在實(shí)際開發(fā)中,我們可以通過指定/Zp編譯選項(xiàng)來更改編譯器的對齊規(guī)則。比如指定/Zpn(VC7.1中n可以是1、2、4、8、16)就是告訴編譯器最大對齊模數(shù)是n。在這種情況下,所有小于等于n字節(jié)的基本數(shù)據(jù)類型的對齊規(guī)則與默認(rèn)的一樣,但是大于n個字節(jié)的數(shù)據(jù)類型的對齊模數(shù)被限制為n。事實(shí)上,VC7.1的默認(rèn)對齊選項(xiàng)就相當(dāng)于/Zp8。仔細(xì)看看MSDN對這個選項(xiàng)的描述,會發(fā)現(xiàn)它鄭重告誡了程序員不要在MIPS和Alpha平臺上用/Zp1和/Zp2選項(xiàng),也不要在16位平臺上指定/Zp4和/Zp8(想想為什么?)。改變編譯器的對齊選項(xiàng),對照程序運(yùn)行結(jié)果重新分析上面4種結(jié)構(gòu)體的內(nèi)存布局將是一個很好的復(fù)習(xí)。

??? 到了這里,我們可以回答本文提出的最后一個問題了。結(jié)構(gòu)體的內(nèi)存布局依賴于CPU、操作系統(tǒng)、編譯器及編譯時(shí)的對齊選項(xiàng),而你的程序可能需要運(yùn)行在多種平臺上,你的源代碼可能要被不同的人用不同的編譯器編譯(試想你為別人提供一個開放源碼的庫),那么除非絕對必需,否則你的程序永遠(yuǎn)也不要依賴這些詭異的內(nèi)存布局。順便說一下,如果一個程序中的兩個模塊是用不同的對齊選項(xiàng)分別編譯的,那么它很可能會產(chǎn)生一些非常微妙的錯誤。如果你的程序確實(shí)有很難理解的行為,不防仔細(xì)檢查一下各個模塊的編譯選項(xiàng)。

??? 思考題:請分析下面幾種結(jié)構(gòu)體在你的平臺上的內(nèi)存布局,并試著尋找一種合理安排字段聲明順序的方法以盡量節(jié)省內(nèi)存空間。

??? A. struct P1 { int a; char b; int c; char d; };
??? B. struct P2 { int a; char b; char c; int d; };
??? C. struct P3 { short a[3]; char b[3]; };
??? D. struct P4 { short a[3]; char *b[3]; };
??? E. struct P5 { struct P2 *a; char b; struct P1 a[2];? };

參考資料:

??? 【1】《深入理解計(jì)算機(jī)系統(tǒng)(修訂版)》,
???????? (著)Randal E.Bryant; David O'Hallaron,
???????? (譯)龔奕利 雷迎春,
???????? 中國電力出版社,2004
???
??? 【2】《C: A Reference Manual》(影印版),
???????? (著)Samuel P.Harbison; Guy L.Steele,
???????? 人民郵電出版社,2003

posted on 2006-05-28 16:15 saga.constantine 閱讀(1108) 評論(0)  編輯 收藏 引用 所屬分類: 轉(zhuǎn)的貼
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲天堂av在线免费观看| 久久一区二区三区国产精品| 欧美在线电影| 亚洲一区在线免费| 先锋资源久久| 久久久久久久一区| 欧美国产精品日韩| 国产精品国产三级国产普通话99| 欧美日韩亚洲不卡| 国产日韩欧美精品一区| 在线播放日韩专区| 亚洲靠逼com| 欧美一级专区免费大片| 蜜桃av一区二区三区| 亚洲国产成人91精品| 亚洲日本欧美| 欧美亚洲一区三区| 欧美国产精品久久| 国产精品欧美风情| 在线观看日韩www视频免费| 亚洲日本欧美| 久久国产99| 亚洲精品一品区二品区三品区| 亚洲一级黄色av| 巨乳诱惑日韩免费av| 国产精品av久久久久久麻豆网| 国产欧美日韩综合一区在线观看| 亚洲第一区中文99精品| 亚洲欧美国产日韩天堂区| 女生裸体视频一区二区三区| 日韩一二在线观看| 久久久综合激的五月天| 99精品视频免费全部在线| 欧美精品久久一区| 狠狠色综合网| 性伦欧美刺激片在线观看| 亚洲成色777777女色窝| 亚洲欧美一区在线| 国产精品va在线播放| 亚洲大胆av| 久久中文字幕一区| 香蕉久久夜色精品国产使用方法| 欧美成人69av| 亚洲电影在线免费观看| 久久久国产91| 欧美一级二级三级蜜桃| 欧美性生交xxxxx久久久| 日韩一级不卡| 欧美国产亚洲视频| 久久美女性网| 激情五月婷婷综合| 久久久一本精品99久久精品66| aa日韩免费精品视频一| 欧美1区3d| 亚洲肉体裸体xxxx137| 欧美成人精品在线播放| 久久精品在这里| 久久成人资源| 欧美在线不卡| 欧美国产欧美综合| 久久一区二区三区超碰国产精品| 日韩亚洲精品在线| 久久夜色精品国产噜噜av| 国产精品久久久久秋霞鲁丝 | 欧美一级黄色网| 欧美日韩精品免费看| 亚洲日韩中文字幕在线播放| 亚洲第一伊人| 欧美激情一区二区三区四区| 亚洲茄子视频| 91久久中文字幕| 欧美涩涩视频| 香蕉视频成人在线观看| 亚洲欧美日韩综合| 激情综合电影网| 亚洲成人在线网站| 欧美日韩在线视频首页| 亚洲欧美色一区| 欧美专区一区二区三区| 亚洲国产日本| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产精品男女猛烈高潮激情| 久久精品国产精品亚洲精品| 久久夜色精品国产欧美乱极品| 亚洲国产欧美日韩| 亚洲第一福利视频| 91久久精品美女高潮| 欧美乱在线观看| 久久精品国产99精品国产亚洲性色| 欧美在线观看你懂的| 91久久久一线二线三线品牌| 日韩视频免费在线观看| 国产精品腿扒开做爽爽爽挤奶网站| 久久免费国产精品| 欧美日韩不卡在线| 久久精品中文字幕免费mv| 欧美成在线观看| 久久国内精品视频| 欧美精品一线| 久久永久免费| 欧美视频一区二区| 嫩草影视亚洲| 国产视频自拍一区| 日韩视频一区二区在线观看 | 亚洲电影在线播放| 日韩亚洲成人av在线| 亚洲大片在线观看| 午夜激情亚洲| 亚洲一区二区高清| 欧美aⅴ一区二区三区视频| 久久都是精品| 一级日韩一区在线观看| 影音先锋日韩精品| 亚洲午夜高清视频| 亚洲精品久久视频| 久热国产精品| 亚洲成人影音| 亚洲欧美一级二级三级| 在线午夜精品自拍| 另类欧美日韩国产在线| 欧美专区在线播放| 国产精品青草综合久久久久99| 亚洲国产日日夜夜| 精品动漫3d一区二区三区| 亚洲一级二级在线| 亚洲在线观看免费| 国产精品成人av性教育| 欧美黄色一区| 国产综合精品一区| 欧美在线观看视频| 久久精品亚洲乱码伦伦中文| 国产精品综合色区在线观看| 在线一区二区三区四区五区| 亚洲网站视频福利| 欧美日韩影院| 亚洲裸体在线观看| 亚洲午夜电影在线观看| 欧美日韩在线另类| 在线视频亚洲| 欧美一区二区三区日韩| 国产区欧美区日韩区| 亚洲综合清纯丝袜自拍| 亚洲欧美激情视频在线观看一区二区三区| 欧美激情精品久久久久| 亚洲国产欧美不卡在线观看| 亚洲精品免费在线| 欧美日韩伦理在线| 亚洲午夜未删减在线观看| 午夜精品久久久久久99热| 国产麻豆精品视频| 黄色精品网站| 先锋影音网一区二区| 国产精品日韩| 久久久久一区二区| 亚洲激情亚洲| 亚洲欧美日韩在线播放| 国产日韩欧美亚洲一区| 老司机aⅴ在线精品导航| 亚洲经典三级| 欧美在线啊v一区| 亚洲第一伊人| 欧美日韩一区二区三区高清| 亚洲一区国产视频| 嫩草国产精品入口| 亚洲毛片在线看| 国产欧美日本一区二区三区| 久久久久久久久久看片| 亚洲国产合集| 欧美在线视频观看| 亚洲经典一区| 国产精品伦一区| 欧美成人日本| 欧美亚洲色图校园春色| 亚洲成人资源| 久久久91精品国产一区二区三区| 亚洲高清自拍| 国产伦精品一区二区三区在线观看| 午夜精品久久久久久久白皮肤| 蜜臀久久久99精品久久久久久| 欧美日韩情趣电影| av成人天堂| 亚洲自啪免费| 99精品福利视频| 国产精品剧情在线亚洲| 亚洲肉体裸体xxxx137| 亚洲一区二区3| 国产精品男gay被猛男狂揉视频| 国产亚洲在线| 亚洲精品久久久久久下一站| 亚洲欧洲在线播放| 亚洲大胆人体视频| 国产精品久久久久一区二区三区共 | 美日韩精品视频免费看| 亚洲日韩视频| 欧美国产综合视频| 久久一区二区视频| 亚洲你懂的在线视频| 亚洲免费成人av电影| 在线成人激情黄色| 国产一区二区看久久|