• <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>

              C++博客 :: 首頁(yè) :: 聯(lián)系 ::  :: 管理
              163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(48)

            我參與的團(tuán)隊(duì)

            搜索

            •  

            積分與排名

            • 積分 - 399102
            • 排名 - 59

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜


                首先請(qǐng)大家先看下面代碼:
                typedef struct
                {
                  UINT32  NumElements;
                  union
                  {
                     UINT32  ObjectHandle;
                   }Entry;
                 }STR_ARRAY, *PSTR_ARRAY;

                還有這兩句#pragma pack(push, 1)
                #pragma pack(pop)
                #pragma  pack( [ n ] )

                該指令指定結(jié)構(gòu)和聯(lián)合成員的緊湊對(duì)齊。而一個(gè)完整的轉(zhuǎn)換單元的結(jié)構(gòu)和聯(lián)合的緊湊對(duì)齊由/ Z p 選項(xiàng)設(shè)置。緊湊對(duì)齊用p a c e 編譯指示在數(shù)據(jù)說(shuō)明層設(shè)置。該編譯指示在其出現(xiàn)后的第一個(gè)結(jié)構(gòu)或聯(lián)合說(shuō)明處生效。該編譯指示對(duì)定義無(wú)效。當(dāng)你使用#pragma  pack ( n ) 時(shí), 這里n 為1 、2 、4 、8 或1 6 。第一個(gè)結(jié)構(gòu)成員之后的每個(gè)結(jié)構(gòu)成員都被存儲(chǔ)在更小的成員類型或n 字節(jié)界限內(nèi)。如果你使用無(wú)參量的#pragma  pack , 結(jié)構(gòu)成員被緊湊為以/ Z p 指定的值。該缺省/ Z p 緊湊值為/ Z p 8 。

                編譯器也支持以下增強(qiáng)型語(yǔ)法:
                #pragma  pack( [ [ { p u s h | p o p } , ] [ 標(biāo)識(shí)符, ] ] [ n] )若不同的組件使用p a c k 編譯指示指定不同的緊湊對(duì)齊, 這個(gè)語(yǔ)法允許你把程序組件組合為一個(gè)單獨(dú)的轉(zhuǎn)換單元。帶p u s h 參量的p a c k 編譯指示的每次出現(xiàn)將當(dāng)前的緊湊對(duì)齊存儲(chǔ)到一個(gè)內(nèi)部編譯器堆棧中。編譯指示的參量表從左到右讀取。如果你使用p u s h , 則當(dāng)前緊湊值被存儲(chǔ)起來(lái); 如果你給出一個(gè)n 的值, 該值將成為新的緊湊值。若你指定一個(gè)
            標(biāo)識(shí)符, 即你選定一個(gè)名稱, 則該標(biāo)識(shí)符將和這個(gè)新的的緊湊值聯(lián)系起來(lái)。帶一個(gè)p o p 參量的p a c k 編譯指示的每次出現(xiàn)都會(huì)檢索內(nèi)部編譯器堆棧頂?shù)闹?并且使該值為新的緊湊對(duì)齊值。如果你使用p o p 參量且內(nèi)部編譯器堆棧是空的,則緊湊值為命令行給定的值, 并且將產(chǎn)生一個(gè)警告信息。若你使用p o p 且指定一
            個(gè)n 的值, 該值將成為新的緊湊值。若你使用p o p 且指定一個(gè)標(biāo)識(shí)符,  所有存儲(chǔ)在堆棧中的值將從棧中刪除, 直到找到一個(gè)匹配的標(biāo)識(shí)符, 這個(gè)與標(biāo)識(shí)符相關(guān)的緊湊值也從棧中移出, 并且這個(gè)僅在標(biāo)識(shí)符入棧之前存在的緊湊值成為新的緊湊值。如果未找到匹配的標(biāo)識(shí)符, 將使用命令行設(shè)置的緊湊值, 并且將產(chǎn)生一個(gè)一級(jí)警告。缺省緊湊對(duì)齊為8 。p a c k 編譯指示的新的增強(qiáng)功能讓你編寫(xiě)頭文件, 確保在遇到該頭文件的前后的緊湊值是一樣的。

                什么是內(nèi)存對(duì)齊

                考慮下面的結(jié)構(gòu):

                     struct foo
                     {
                       char c1;
                       short s;
                       char c2;
                       int i;
                      };
               
                假設(shè)這個(gè)結(jié)構(gòu)的成員在內(nèi)存中是緊湊排列的,假設(shè)c1的地址是0,那么s的地址就應(yīng)該是1,c2的地址就是3,i的地址就是4。也就是
                c1 00000000, s 00000001, c2 00000003, i 00000004。

                可是,我們?cè)赩isual c/c++ 6中寫(xiě)一個(gè)簡(jiǎn)單的程序:

                     struct foo a;
                printf("c1 %p, s %p, c2 %p, i %p\n",
                    (unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
                    (unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
                    (unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
                    (unsigned int)(void*)&a.i - (unsigned int)(void*)&a);
                運(yùn)行,輸出:
                     c1 00000000, s 00000002, c2 00000004, i 00000008。

                為什么會(huì)這樣?這就是內(nèi)存對(duì)齊而導(dǎo)致的問(wèn)題。

            為什么會(huì)有內(nèi)存對(duì)齊

                以下內(nèi)容節(jié)選自《Intel Architecture 32 Manual》。
                字,雙字,和四字在自然邊界上不需要在內(nèi)存中對(duì)齊。(對(duì)字,雙字,和四字來(lái)說(shuō),自然邊界分別是偶數(shù)地址,可以被4整除的地址,和可以被8整除的地址。)
                無(wú)論如何,為了提高程序的性能,數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對(duì)齊。原因在于,為了訪問(wèn)未對(duì)齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問(wèn);然而,對(duì)齊的內(nèi)存訪問(wèn)僅需要一次訪問(wèn)。
                一個(gè)字或雙字操作數(shù)跨越了4字節(jié)邊界,或者一個(gè)四字操作數(shù)跨越了8字節(jié)邊界,被認(rèn)為是未對(duì)齊的,從而需要兩次總線周期來(lái)訪問(wèn)內(nèi)存。一個(gè)字起始地址是奇數(shù)但卻沒(méi)有跨越字邊界被認(rèn)為是對(duì)齊的,能夠在一個(gè)總線周期中被訪問(wèn)。
                某些操作雙四字的指令需要內(nèi)存操作數(shù)在自然邊界上對(duì)齊。如果操作數(shù)沒(méi)有對(duì)齊,這些指令將會(huì)產(chǎn)生一個(gè)通用保護(hù)異常(#GP)。雙四字的自然邊界是能夠被16 整除的地址。其他的操作雙四字的指令允許未對(duì)齊的訪問(wèn)(不會(huì)產(chǎn)生通用保護(hù)異常),然而,需要額外的內(nèi)存總線周期來(lái)訪問(wèn)內(nèi)存中未對(duì)齊的數(shù)據(jù)。

            編譯器對(duì)內(nèi)存對(duì)齊的處理

                缺省情況下,c/c++編譯器默認(rèn)將結(jié)構(gòu)、棧中的成員數(shù)據(jù)進(jìn)行內(nèi)存對(duì)齊。因此,上面的程序輸出就變成了:
            c1 00000000, s 00000002, c2 00000004, i 00000008。
            編譯器將未對(duì)齊的成員向后移,將每一個(gè)都成員對(duì)齊到自然邊界上,從而也導(dǎo)致了整個(gè)結(jié)構(gòu)的尺寸變大。盡管會(huì)犧牲一點(diǎn)空間(成員之間有空洞),但提高了性能。
            也正是這個(gè)原因,我們不可以斷言sizeof(foo) == 8。在這個(gè)例子中,sizeof(foo) == 12。

            如何避免內(nèi)存對(duì)齊的影響

                那么,能不能既達(dá)到提高性能的目的,又能節(jié)約一點(diǎn)空間呢?有一點(diǎn)小技巧可以使用。比如我們可以將上面的結(jié)構(gòu)改成:

                struct bar
                {
                    char c1;
                    char c2;
                    short s;
                    int i;
                };
                這樣一來(lái),每個(gè)成員都對(duì)齊在其自然邊界上,從而避免了編譯器自動(dòng)對(duì)齊。在這個(gè)例子中,sizeof(bar) == 8。

                這個(gè)技巧有一個(gè)重要的作用,尤其是這個(gè)結(jié)構(gòu)作為API的一部分提供給第三方開(kāi)發(fā)使用的時(shí)候。第三方開(kāi)發(fā)者可能將編譯器的默認(rèn)對(duì)齊選項(xiàng)改變,從而造成這個(gè)結(jié)構(gòu)在你的發(fā)行的DLL中使用某種對(duì)齊方式,而在第三方開(kāi)發(fā)者哪里卻使用另外一種對(duì)齊方式。這將會(huì)導(dǎo)致重大問(wèn)題。
                比如,foo結(jié)構(gòu),我們的DLL使用默認(rèn)對(duì)齊選項(xiàng),對(duì)齊為
            c1 00000000, s 00000002, c2 00000004, i 00000008,同時(shí)sizeof(foo) == 12。
            而第三方將對(duì)齊選項(xiàng)關(guān)閉,導(dǎo)致
                c1 00000000, s 00000001, c2 00000003, i 00000004,同時(shí)sizeof(foo) == 8。

            如何使用c/c++中的對(duì)齊選項(xiàng)

                vc6中的編譯選項(xiàng)有 /Zp[1|2|4|8|16] ,/Zp1表示以1字節(jié)邊界對(duì)齊,相應(yīng)的,/Zpn表示以n字節(jié)邊界對(duì)齊。n字節(jié)邊界對(duì)齊的意思是說(shuō),一個(gè)成員的地址必須安排在成員的尺寸的整數(shù)倍地址上或者是n的整數(shù)倍地址上,取它們中的最小值。也就是:
                min ( sizeof ( member ),  n)
                實(shí)際上,1字節(jié)邊界對(duì)齊也就表示了結(jié)構(gòu)成員之間沒(méi)有空洞。
                /Zpn選項(xiàng)是應(yīng)用于整個(gè)工程的,影響所有的參與編譯的結(jié)構(gòu)。
                要使用這個(gè)選項(xiàng),可以在vc6中打開(kāi)工程屬性頁(yè),c/c++頁(yè),選擇Code Generation分類,在Struct member alignment可以選擇。

                要專門針對(duì)某些結(jié)構(gòu)定義使用對(duì)齊選項(xiàng),可以使用#pragma pack編譯指令。指令語(yǔ)法如下:
            #pragma pack( [ show ] | [ push | pop ] [, identifier ] , n  )
                意義和/Zpn選項(xiàng)相同。比如:

                #pragma pack(1)
                struct foo_pack
                {
                    char c1;
                    short s;
                    char c2;
                    int i;
                };
                #pragma pack()

                棧內(nèi)存對(duì)齊

                我們可以觀察到,在vc6中棧的對(duì)齊方式不受結(jié)構(gòu)成員對(duì)齊選項(xiàng)的影響。(本來(lái)就是兩碼事)。它總是保持對(duì)齊,而且對(duì)齊在4字節(jié)邊界上。

                驗(yàn)證代碼

                #include <stdio.h>

                struct foo
                {
                    char c1;
                    short s;
                    char c2;
                    int i;
                };

                struct bar
                {
                    char c1;
                    char c2;
                    short s;
                    int i;
                };

                #pragma pack(1)
                struct foo_pack
                {
                    char c1;
                    short s;
                    char c2;
                    int i;
                };
                #pragma pack()


                int main(int argc, char* argv[])
                {
                    char c1;
                    short s;
                    char c2;
                    int i;

                struct foo a;
                struct bar b;
                struct foo_pack p;

                printf("stack c1 %p, s %p, c2 %p, i %p\n",
                    (unsigned int)(void*)&c1 - (unsigned int)(void*)&i,
                    (unsigned int)(void*)&s - (unsigned int)(void*)&i,
                    (unsigned int)(void*)&c2 - (unsigned int)(void*)&i,
                    (unsigned int)(void*)&i - (unsigned int)(void*)&i);

                printf("struct foo c1 %p, s %p, c2 %p, i %p\n",
                    (unsigned int)(void*)&a.c1 - (unsigned int)(void*)&a,
                    (unsigned int)(void*)&a.s - (unsigned int)(void*)&a,
                    (unsigned int)(void*)&a.c2 - (unsigned int)(void*)&a,
                    (unsigned int)(void*)&a.i - (unsigned int)(void*)&a);

                printf("struct bar c1 %p, c2 %p, s %p, i %p\n",
                    (unsigned int)(void*)&b.c1 - (unsigned int)(void*)&b,
                    (unsigned int)(void*)&b.c2 - (unsigned int)(void*)&b,
                    (unsigned int)(void*)&b.s - (unsigned int)(void*)&b,
                    (unsigned int)(void*)&b.i - (unsigned int)(void*)&b);

                printf("struct foo_pack c1 %p, s %p, c2 %p, i %p\n",
                    (unsigned int)(void*)&p.c1 - (unsigned int)(void*)&p,
                    (unsigned int)(void*)&p.s - (unsigned int)(void*)&p,
                    (unsigned int)(void*)&p.c2 - (unsigned int)(void*)&p,
                    (unsigned int)(void*)&p.i - (unsigned int)(void*)&p);

                printf("sizeof foo is %d\n", sizeof(foo));
                printf("sizeof bar is %d\n", sizeof(bar));
                printf("sizeof foo_pack is %d\n", sizeof(foo_pack));
               
                return 0;


                }




            posted on 2007-12-23 20:03 sdfasdf 閱讀(17371) 評(píng)論(1)  編輯 收藏 引用 所屬分類: C++

            Feedback

            # re: 關(guān)于pragma pack的用法(四) C++中的內(nèi)存對(duì)齊問(wèn)題 2008-01-03 20:01 guojianlee
            不同編譯器的,的內(nèi)存對(duì)齊的參數(shù)選項(xiàng)不同,要注意。上次因?yàn)檫@個(gè)問(wèn)題。搞了半死  回復(fù)  更多評(píng)論
              

            欧美大战日韩91综合一区婷婷久久青草 | 中文字幕久久精品| 国产精品99久久精品爆乳| 久久久精品人妻无码专区不卡| 狠狠88综合久久久久综合网 | 青青青青久久精品国产h久久精品五福影院1421 | 国产国产成人精品久久| 久久精品国产99久久久古代| 精品久久人妻av中文字幕| 久久99国产一区二区三区| 午夜精品久久久久久久久| 天天爽天天爽天天片a久久网| 久久久黄片| 日本精品久久久久中文字幕| 三级三级久久三级久久| 精品久久久久久无码人妻热| 久久亚洲美女精品国产精品| 激情综合色综合久久综合| 国产精品久久久久aaaa| 九九精品久久久久久噜噜| 办公室久久精品| 久久国产精品久久久| 国产精品久久久久无码av| 国产成人精品三上悠亚久久| 欧美激情精品久久久久久| 91久久九九无码成人网站| 99久久精品午夜一区二区| 色婷婷综合久久久中文字幕| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 亚洲国产精品无码久久久秋霞2| 久久夜色精品国产噜噜噜亚洲AV | 国产亚洲精久久久久久无码77777| 办公室久久精品| 久久se这里只有精品| 91久久精品国产免费直播| 99热都是精品久久久久久| 久久精品国产一区二区三区日韩| 亚洲精品无码久久久久去q| 无码人妻久久一区二区三区免费丨 | 久久国产成人亚洲精品影院| 久久99国产精品尤物|