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

            tbwshc

            tbw

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              95 Posts :: 8 Stories :: 3 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(4)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            最近在調試中遇到點內存對齊的問題,別人問我是怎么回事,我趕緊偷偷查了一下,記錄下來。

            不論是C、C++對于內存對齊的問題在原理上是一致的,對齊的原因和表現,簡單總結一下,以便朋友們共享。

            一、內存對齊的原因
            大部分的參考資料都是如是說的:
            1、平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數據的;某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。
            2、性能原因:數據結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。

               也有的朋友說,內存對齊出于對讀取的效率和數據的安全的考慮,我覺得也有一定的道理。

            二、對齊規則
                每個特定平臺上的編譯器都有自己的默認“對齊系數”(也叫對齊模數)。比如32位windows平臺下,VC默認是按照8bytes對齊的(VC->Project->settings->c/c++->Code Generation中的truct member alignment 值默認是8),程序員可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一系數,其中的n就是你要指定的“對齊系數”。

                在嵌入式環境下,對齊往往與數據類型有關,特別是C編譯器對缺省的結構成員自然對屆條件為“N字節對 齊”,N即該成員數據類型的長度。如int型成員的自然對界條件為4字節對齊,而double類型的結構成員的自然對界條件為8字節對齊。若該成員的起始 偏移不位于該成員的“默認自然對界條件”上,則在前一個節面后面添加適當個數的空字節。C編譯器缺省的結構整體的自然對界條件為:該結構所有成員中要求的 最大自然對界條件。若結構體各成員長度之和不為“結構整體自然對界條件的整數倍,則在最后一個成員后填充空字節。

                那么可以得到如下的小結:

            類型 對齊方式(變量存放的起始地址相對于結構的起始地址的偏移量)
            Char    偏移量必須為sizeof(char)即1的倍數
            Short   偏移量必須為sizeof(short)即2的倍數
            int     偏移量必須為sizeof(int)即4的倍數
            float   偏移量必須為sizeof(float)即4的倍數
            double  偏移量必須為sizeof(double)即8的倍數

               各成員變量在存放的時候根據在結構中出現的順序依次申請空間,同時按照上面的對齊方式調整位置,空缺的字節編譯器會自動填充。同時為了確保結構的大小為結 構的字節邊界數(即該結構中占用最大空間的類型所占用的字節數)的倍數,所以在為最后一個成員變量申請空間后,還會根據需要自動填充空缺的字節,也就是 說:結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之后加上填充字節。對于char數組,字節寬度仍然認為為1。

               對于下述的一個結構體,其對齊方式為:

            struct Node1{

                double m1;
                char m2;
                int m3;
            };

              對于第一個變量m1,sizeof(double)=8個字節;接下來為第二個成員m2分配空間,這時下一個可以分配的地址對于結構的起始地址的偏移量為8,是sizeof(char)的倍數,所以把m2存放在偏移量為8的地方滿足對齊方式,該成員變量占用 sizeof(char)=1個字節;接下來為第三個成員m3分配空間,這時下一個可以分配的地址對于結構的起始地址的偏移量為9,不是sizeof (int)=4的倍數,為了滿足對齊方式對偏移量的約束問題,自動填充3個字節(這三個字節沒有放什么東西),這時下一個可以分配的地址對于結構的起始地址的偏移量為12,剛好是sizeof(int), 由于8+4+4 = 16恰好是結構體中最大空間類型double(8)的倍數,所以sizeof(Node1) =16.

             

            typedef struct{

                char a;

                int b;

                char c;

            }Node2;

                成員a占一個字節,所以a放在了第1位的位置;由于第二個變量b占4個字節,為保證起始位置是4(sizeof(b))的倍數,所以需要在a后面填充3個 字節,也就是b放在了從第5位到第8位的位置,然后就是c放在了9的位置,此時4+4+1=9。接下來考慮字節邊界數,9并不是最大空間類型int(4) 的倍數,應該取大于9且是4的的最小整數12,所以sizeof(Node2) = 12.
            typedef struct{

                char a;

                char b;

                int c;

            }Node3;

               明顯地:sizeof(Node3) = 8

               對于結構體A中包含結構體B的情況,將結構體A中的結構體成員B中的最寬的數據類型作為該結構體成員B的數據寬度,同時結構體成員B必須滿足上述對齊的規定。

               要注意在VC中有一個對齊系數的概念,若設置了對齊系數,那么上述描述的對齊方式,則不適合。

               例如:

            1字節對齊(#pragma pack(1))
            輸出結果:sizeof(struct test_t) = 8 [兩個編譯器輸出一致]
            分析過程:
            成員數據對齊
            #pragma pack(1)
            struct test_t {
                int a;
                char b;
                short c;
                char d;
            };
            #pragma pack()
            成員總大小=8;

             

            2字節對齊(#pragma pack(2))
            輸出結果:sizeof(struct test_t) = 10 [兩個編譯器輸出一致]
            分析過程:
            成員數據對齊
            #pragma pack(2)
            struct test_t {
                int a;
                char b;
                short c;
                char d;
            };
            #pragma pack()
            成員總大小=9;

             

            4字節對齊(#pragma pack(4))
            輸出結果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
            分析過程:
            1) 成員數據對齊
            #pragma pack(4)
            struct test_t { //按幾對齊, 偏移量為后邊第一個取模為零的。
            int a;
            char b;
            short c;
            char d;
            };
            #pragma pack()
            成員總大小=9;

             

            8字節對齊(#pragma pack(8))
            輸出結果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
            分析過程:
            成員數據對齊
            #pragma pack(8)
            struct test_t {
            int a;
            char b;
            short c;
            char d;
            };
            #pragma pack()
            成員總大小=9;

             

            16字節對齊(#pragma pack(16))
            輸出結果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
            分析過程:
            1) 成員數據對齊
            #pragma pack(16)
            struct test_t {
            int a;
            char b;
            short c;
            char d;
            };
            #pragma pack()
            成員總大小=9;

             

            至于8字節對齊和16字節對齊,我覺得這兩個例子取得不好,沒有太大的參考意義。

            (x666f)

            posted on 2013-07-10 17:09 tbwshc 閱讀(251) 評論(0)  編輯 收藏 引用
            久久久精品国产sm调教网站| 人人狠狠综合久久亚洲88| 久久电影网一区| 久久Av无码精品人妻系列| 久久精品日日躁夜夜躁欧美| 久久天天躁狠狠躁夜夜av浪潮 | 中文字幕亚洲综合久久菠萝蜜| 91亚洲国产成人久久精品网址| 国产亚洲综合久久系列| 久久成人国产精品| 久久久久久久综合日本亚洲| 国产精品无码久久久久久| 久久久久综合网久久| 国产精品综合久久第一页 | 久久精品国产精品亚洲人人| 99久久国产热无码精品免费久久久久 | 久久99精品久久久久久野外 | 久久精品成人免费看| 日本三级久久网| 性做久久久久久久久| 久久精品国产亚洲av麻豆蜜芽| 人人狠狠综合久久88成人| 狠狠色噜噜狠狠狠狠狠色综合久久| 9191精品国产免费久久| 香蕉久久永久视频| 亚洲AV无码久久精品色欲| 国内精品久久久久影院优| 成人精品一区二区久久| 99久久综合国产精品免费| 77777亚洲午夜久久多喷| 久久精品国产99久久香蕉| 99久久国产精品免费一区二区| 99久久精品国内| 中文字幕无码免费久久| 狠狠色丁香婷综合久久| 久久精品国产亚洲αv忘忧草| 久久国产色AV免费看| 伊人伊成久久人综合网777| 9久久9久久精品| 国产亚洲精久久久久久无码77777 国产亚洲精品久久久久秋霞 | 日韩影院久久|