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

saga's blog

突出重點,系統全面,不留死角

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

公告

QQ:34O859O5

常用鏈接

留言簿(15)

搜索

  •  

積分與排名

  • 積分 - 212569
  • 排名 - 124

最新評論

閱讀排行榜

評論排行榜

選擇自 soloist 的 Blog 作者:不詳? 如原作者發現并不允許轉載請通知我,我會刪除!


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

??? 首先,至少有一點可以肯定,那就是ANSI C保證結構體中各字段在內存中出現的位置是隨它們的聲明順序依次遞增的,并且第一個字段的首地址等于整個結構體實例的首地址。比如有這樣一個結構體:
?
? 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);
? // 上述斷言一定不會失敗

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

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

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

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

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

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

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

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

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

??? 或許你認為MS2比MS1的情況要簡單,它的布局應該就是

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

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

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

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

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

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

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

??? 好的,現在你已經掌握了結構體內存布局的基本準則,嘗試分析一個稍微復雜點的類型吧。

? 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字段應從偶數地址開始,所以a的后面填充一個字節,而sizeof(double)等于8,c
字段要從8倍數地址開始,前面的a、b字段加上填充字節已經有4 bytes,所以b后面再填充4個字節就可以保證c字段的對齊要求了。sizeof(MS3)等于16,b的偏移是2,c的偏移是8。接著看看結構體中字段還是結構類型的情況:

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

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

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

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

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

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

??? 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】《深入理解計算機系統(修訂版)》,
???????? (著)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 閱讀(1109) 評論(0)  編輯 收藏 引用 所屬分類: 轉的貼
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美福利视频| 亚洲一区中文字幕在线观看| 日韩午夜在线播放| 亚洲人成在线播放| 日韩亚洲综合在线| 亚洲精品一二三区| 一区二区欧美日韩| 欧美一级成年大片在线观看| 性色一区二区| 免费成人黄色片| 亚洲电影免费观看高清完整版在线| 国产亚洲欧美激情| 国产一本一道久久香蕉| 一色屋精品亚洲香蕉网站| 亚洲国产毛片完整版| 日韩一级二级三级| 久久福利精品| 亚洲国产一区二区三区青草影视| 亚洲另类自拍| 一区二区三区日韩在线观看| 一本一本久久a久久精品综合麻豆| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 欧美日韩精品免费观看视频| 欧美特黄一级| 国产偷国产偷亚洲高清97cao | 正在播放亚洲| 久久免费偷拍视频| 亚洲精品国产精品国自产观看浪潮 | 久久久人成影片一区二区三区观看 | 牛牛国产精品| 中日韩视频在线观看| 久久在精品线影院精品国产| 国产精品theporn| 亚洲激情在线视频| 久久国产精品久久精品国产| 亚洲黄色在线视频| 久久久天天操| 国产日韩1区| 亚洲视频在线观看网站| 国产精品国产精品| 激情久久影院| 亚洲综合色婷婷| 91久久亚洲| 久久一区二区三区四区| 国产精品性做久久久久久| 亚洲国产一区在线观看| 久久久久国产精品一区三寸| 伊人久久大香线| 欧美伊久线香蕉线新在线| 亚洲精品一区二区三区蜜桃久| 久久精品国产99国产精品澳门| 国产精品色在线| 亚洲一区免费网站| 亚洲美女中出| 欧美日韩国产在线观看| 亚洲人成网在线播放| 久久综合一区二区三区| 欧美一区二区视频97| 国产精品美女| 欧美一级视频免费在线观看| 亚洲少妇中出一区| 国产精品卡一卡二| 亚洲欧美一区二区三区久久| 这里只有精品电影| 国产精品嫩草影院av蜜臀| 亚洲欧美激情精品一区二区| 在线亚洲国产精品网站| 国产精品欧美精品| 久久精品国产清高在天天线| 欧美一区二区三区免费观看| 国外成人在线视频| 美国三级日本三级久久99| 久久亚洲电影| 亚洲精品黄色| 一本一本大道香蕉久在线精品| 欧美视频在线免费看| 新67194成人永久网站| 欧美有码视频| 亚洲黄网站在线观看| 亚洲人成毛片在线播放| 国产精品大片wwwwww| 久久久久久久久综合| 免费久久99精品国产自| 亚洲午夜黄色| 久久超碰97人人做人人爱| 亚洲三级电影在线观看| 一区二区日韩| 狠狠色狠狠色综合系列| 亚洲国产精品久久久久| 国产精品乱人伦一区二区 | 尤物yw午夜国产精品视频| 欧美国产日韩二区| 欧美三级视频| 蜜臀av国产精品久久久久| 欧美日韩成人在线播放| 久久aⅴ国产欧美74aaa| 免费高清在线视频一区·| 亚洲精品少妇| 国产精品亚洲а∨天堂免在线| ●精品国产综合乱码久久久久| 久久久精品一区| 亚洲欧美日韩国产中文在线| 久久国产天堂福利天堂| 亚洲麻豆一区| 久久成人羞羞网站| 亚洲美女中出| 免费在线看成人av| 噜噜噜噜噜久久久久久91| 国产一区二区三区的电影| 欧美日韩另类视频| 欧美少妇一区二区| 久久天天躁夜夜躁狠狠躁2022| 久久久久久久综合日本| 99视频在线精品国自产拍免费观看 | 亚洲激情在线激情| 国产精品普通话对白| 亚洲国产精选| 激情六月婷婷久久| 一区二区三区视频在线观看| 亚洲高清视频在线| 欧美在线观看网站| 欧美一区二区国产| 欧美性一区二区| 亚洲精品日韩在线| 亚洲片区在线| 久久久亚洲欧洲日产国码αv | 亚洲福利精品| 久久精品国产999大香线蕉| 欧美一级久久久| 欧美日韩中文字幕在线| 亚洲国产高清aⅴ视频| 永久91嫩草亚洲精品人人| 香蕉久久精品日日躁夜夜躁| 亚洲一区尤物| 国产精品v欧美精品v日韩| 日韩亚洲精品在线| 亚洲视频999| 欧美视频在线观看一区| 在线视频一区二区| 欧美亚洲视频在线观看| 国产精品男gay被猛男狂揉视频| 一本色道久久综合亚洲精品小说| 一区二区三区 在线观看视频| 欧美日韩精品免费观看视一区二区| 亚洲国产精品日韩| 亚洲理论在线观看| 久久精品电影| 国产精品视频专区| 9国产精品视频| 校园激情久久| 国产一区二区三区精品久久久| 午夜在线a亚洲v天堂网2018| 欧美肥婆bbw| 亚洲欧洲三级| 亚洲欧美在线播放| 国产亚洲一区二区三区在线播放| 久久九九精品| 亚洲精品无人区| 亚洲欧美综合另类中字| 国内精品久久久久久久影视麻豆 | 夜夜夜精品看看| 久久国产精品一区二区三区四区 | 91久久中文字幕| 欧美日韩天堂| 欧美中日韩免费视频| 亚洲福利在线视频| 亚洲图片在线观看| 国产一区二区三区免费在线观看 | 一区福利视频| 欧美日韩美女在线| 欧美一区二区日韩| 亚洲国产欧美一区| 久久精品动漫| 亚洲桃花岛网站| 在线观看视频一区| 欧美午夜影院| 久久亚洲欧美| 一区二区三区日韩欧美精品| 久久亚洲国产精品日日av夜夜| 亚洲另类黄色| 国产夜色精品一区二区av| 欧美片第一页| 久久夜色精品国产欧美乱极品| 一本一道久久综合狠狠老精东影业 | 欧美~级网站不卡| 亚洲女性喷水在线观看一区| 亚洲高清视频在线| 欧美在线播放一区| 亚洲午夜免费视频| 亚洲精品免费在线播放| 国产真实乱子伦精品视频| 欧美日韩一区二区三区免费看 | 午夜亚洲福利在线老司机| 亚洲伦理在线| 欧美成人亚洲成人| 久久久青草青青国产亚洲免观| 亚洲一区在线观看视频| 99精品黄色片免费大全| 亚洲国产精品一区| 一区免费观看|