<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          MDK對齊方式設(shè)定

          作者: 時(shí)間:2016-11-27 來源:網(wǎng)絡(luò) 收藏
          __align(4) u8 mem1base[MEM1_MAX_SIZE];

          為何要字節(jié)對齊?

          本文引用地址:http://www.ex-cimer.com/article/201611/322520.htm

          從理論上講似乎對任何類型的變量的訪問可以從任何地址開始,但實(shí)際情況是在訪問特定類型變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問,各個(gè)硬件平臺(tái)對存儲(chǔ)空間的處理上有很大的不同。一些平臺(tái)對某些特定類型的數(shù)據(jù)只能從某些特定地址開始存取。

          MDK 字節(jié)對齊關(guān)鍵字 __packed

          typedef __packed struct abc
          {
          int a;
          int b;
          }strabc;

          vxworks 字節(jié)對齊關(guān)鍵字 _WRS_PACK_ALIGN(1)

          typedefstruct abc
          {
          int a;
          int b;
          }_WRS_PACK_ALIGN(1) strabc;

          (1)什么是字節(jié)對齊
          一個(gè)變量占用 n 個(gè)字節(jié),則該變量的起始地址必須能夠被 n 整除,即: 存放起始地址 % n = 0, 對于結(jié)構(gòu)體而言,這個(gè) n 取其成員種的數(shù)據(jù)類型占空間的值最大的那個(gè)。
          (2)為什么要字節(jié)對齊
          內(nèi)存空間是按照字節(jié)來劃分的,從理論上說對內(nèi)存空間的訪問可以從任何地址開始,但是在實(shí)際上不同架構(gòu)的CPU為了提高訪問內(nèi)存的速度,就規(guī)定了對于某些類 型的數(shù)據(jù)只能從特定的起始位置開始訪問。這樣就決定了各種數(shù)據(jù)類型只能按照相應(yīng)的規(guī)則在內(nèi)存空間中存放,而不能一個(gè)接一個(gè)的順序排列。

          舉個(gè)例子,比如有些平臺(tái)訪問內(nèi)存地址都從偶數(shù)地址開始,對于一個(gè)int型(假設(shè)32位系統(tǒng)),如果從偶數(shù)地址開始的地方存放,這樣一個(gè)讀周期就可以讀出這 個(gè)int數(shù)據(jù),但是如果從奇數(shù)地址開始的地址存放,就需要兩個(gè)讀周期,并對兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到這個(gè)int數(shù)據(jù),這樣明顯降低了讀取 的效率。
          (3)如何進(jìn)行字節(jié)對齊

          每個(gè)成員按其類型的對齊參數(shù)(通常是這個(gè)類型的大小)和指定對齊參數(shù)(不指定則取默認(rèn)值)中較小的一個(gè)對齊,并且結(jié)構(gòu)的長度必須為所用過的所有對齊參數(shù)的整數(shù)倍,不夠就補(bǔ)空字節(jié)。

          這個(gè)規(guī)則有點(diǎn)苦澀,可以把這個(gè)規(guī)則分解一下,前半句的意思先獲得對齊值后與指定對齊值進(jìn)行比較,其中對齊值獲得方式如下:

          1. 數(shù)據(jù)類型的自身對齊值為:對于char型數(shù)據(jù),其自身對齊值為1,對于short型為2,對于int, long, float類型,其自身對齊值為4,對于 double 類型其自身對齊值為8,單位為字節(jié)。
          2.結(jié)構(gòu)體自身對齊值:其成員中自身對齊值最大的那個(gè)值。

          其中指定對齊值獲得方式如下:

          #pragma pack (value)時(shí)的指定對齊值value。

          未指定則取默認(rèn)值。

          后半句的意思是主要是針對于結(jié)構(gòu)體的長度而言,因?yàn)獒槍?shù)據(jù)類型的成員,它僅有一個(gè)對齊參數(shù),其本身的長度、于這個(gè)對齊參數(shù),即1倍。對于結(jié)構(gòu)體而言,它 可能使用了多種數(shù)據(jù)類型,那么這句話翻譯成對齊規(guī)則: 每個(gè)成員的起始地址 % 自身對齊值 = 0,如果不等于 0 則先補(bǔ)空字節(jié)直至這個(gè)表達(dá)式成立。
          換句話說,對于結(jié)構(gòu)體而言,結(jié)構(gòu)體在在內(nèi)存的存放順序用如下規(guī)則即可映射出來:
          (一)每個(gè)成員的起始地址 % 每個(gè)成員的自身對齊值 = 0,如果不等于 0 則先補(bǔ)空字節(jié)直至這個(gè)表達(dá)式成立;
          (二)結(jié)構(gòu)體的長度必須為結(jié)構(gòu)體的自身對齊值的整數(shù)倍,不夠就補(bǔ)空字節(jié)。

          舉個(gè)例子:

          #pragma pack(8)
          struct A{
          char a;
          long b;
          };

          struct B{
          char a;
          struct A b;
          long c;
          };

          struct C{
          char a;
          struct A b;
          double c;
          };

          struct D{
          char a;
          struct A b;
          double c;
          int d;
          };

          struct E{
          char a;
          int b;
          struct A c;
          double d;
          };


          對于 struct A 來說,對于char型數(shù)據(jù),其自身對齊值為1,對于long類型,其自身對齊值為4, 結(jié)構(gòu)體的自身對齊值取其成員最大的對齊值,即大小4。那么struct A 在內(nèi)存中的順序步驟為:
          (1) char a, 地址范圍為0x0000~0x0000,起始地址為0x0000,滿足 0x0000 % 1 = 0,這個(gè)成員字節(jié)對齊了。
          (2) long b, 地址起始位置不能從0x00001開始,因?yàn)?0x0001 % 4 != 0,所以先補(bǔ)空字節(jié),直到0x00003結(jié)束,即補(bǔ)3個(gè)字節(jié)的空字節(jié),從0x00004開始存放b,其地址范圍為0x00004~0x0007.
          (3)此時(shí)成員都存放結(jié)束,結(jié)構(gòu)體長度為8,為結(jié)構(gòu)體自身對齊值的2倍,符合條件(二).
          此時(shí)滿足條件(一)和條件(二),struct A 中各成員在內(nèi)存中的位置為:a*** b ,sizeof(struct A) = 8。(每個(gè)星號(hào)代表一位,成員各自代表自己所占的位,比如a占一位,b占四位)

          對于struct B,里面有個(gè)類型為struct A的成員b自身對齊值為4,對于long類型,其自身對齊值為4. 故struct B的自身對齊值為4。那么struct B 在內(nèi)存中的順序步驟為:
          (1) char a, 地址范圍為0x0000~0x0000,起始地址為0x0000,滿足 0x0000 % 1 = 0,這個(gè)成員字節(jié)對齊了。
          (2) struct A b, 地址起始位置不能從0x00001開始,因?yàn)?0x0001 % 4 != 0,所以先補(bǔ)空字節(jié),直到0x00003結(jié)束,即補(bǔ)3個(gè)字節(jié)的空字節(jié),從0x00004開始存放b,其地址范圍為0x00004~0x00011.
          (3) long c,地址起始位置從0x000012開始, 因?yàn)?0x0012 % 4 = 0,其地址范圍為0x00012~0x0015.
          (4)此時(shí)成員都存放結(jié)束,結(jié)構(gòu)體長度為16,為結(jié)構(gòu)體自身對齊值的4倍,符合條件(二).
          此時(shí)滿足條件(一)和條件(二),struct B 中各成員在內(nèi)存中的位置為:a*** b c ,sizeof(struct C) = 24。(每個(gè)星號(hào)代表一位,成員各自代表自己所占的位,比如a占一位,b占八位,c占四位)
          對于struct C,里面有個(gè)類型為struct A的成員b自身對齊值為4,對于double 類型,其自身對齊值為8. 故struct C的自身對齊值為8。那么struct C 在內(nèi)存中的順序步驟為:
          (1) char a, 地址范圍為0x0000~0x0000,起始地址為0x0000,滿足 0x0000 % 1 = 0,這個(gè)成員字節(jié)對齊了。
          (2) struct A b, 地址起始位置不能從0x00001開始,因?yàn)?0x0001 % 4 != 0,所以先補(bǔ)空字節(jié),直到0x00003結(jié)束,即補(bǔ)3個(gè)字節(jié)的空字節(jié),從0x00004開始存放b,其地址范圍為0x00004~0x00011.
          (3) double c,地址起始位置不能從0x000012開始, 因?yàn)?0x0012 % 8 != 0,所以先補(bǔ)空字節(jié),直到0x000015結(jié)束,即補(bǔ)4個(gè)字節(jié)的空字節(jié),從0x00016開始存放c,其地址范圍為0x00016~0x0023.
          (4)此時(shí)成員都存放結(jié)束,結(jié)構(gòu)體長度為24,為結(jié)構(gòu)體自身對齊值的3倍,符合條件(二).
          此時(shí)滿足條件(一)和條件(二),struct C 中各成員在內(nèi)存中的位置為:a*** b **** c ,sizeof(struct C) = 24。(每個(gè)星號(hào)代表一位,成員各自代表自己所占的位,比如a占一位,b占八位,c占八位)

          對于struct D,自身對齊值為8。前面三個(gè)成員與 struct C 是一致的。對于第四成員d,因?yàn)?0x0024 % 4 = 0, 所以可以從0x0024開始存放d, 其地址范圍為0x00024~0x00027.此時(shí)成員都存放結(jié)束,結(jié)構(gòu)體長度為28,28 不是結(jié)構(gòu)體自身對齊值8的倍數(shù),所以要在后面補(bǔ)四個(gè)空格,即在0x0028~0x0031上補(bǔ)四個(gè)空格。補(bǔ)完了,結(jié)構(gòu)體長度為32, 為結(jié)構(gòu)體自

          身對齊值的4被,,符合條件(二).
          此時(shí)滿足條件(一)和條件(二),struct D 中各成員在內(nèi)存中的位置為:a*** b **** c d **** ,sizeof(struct D) = 32。(每個(gè)星號(hào)代表一位,成員各自代表自己所占的位,比如a占一位,b占八位,c占八位, d占四位)。

          對于struct E 中各成員在內(nèi)存中的位置為:a*** b c d, sizeof(struct E) = 24。(每個(gè)星號(hào)代表一位,成員各自代表自己所占的位,比如a占一位,b占四位,c占八位, d占八位)。
          通過struct D 和 struct E 可以看出,在成員數(shù)量和類型一致的情況,后者的所占空間少于前者,因?yàn)楹笳叩奶畛淇兆止?jié)要少。如果我們在編程時(shí)考慮節(jié)約空間的話,應(yīng)該遵循將變量按照類型 大小從小到大聲明的原則, 這樣盡量減少填補(bǔ)空間。另外,可以在填充空字節(jié)的地方來插入reserved成員, 例如
          struct A
          {
          char a;
          char reserved[3];
          int b;
          };
          這樣做的目的主要是為了對程序員起一個(gè)提示作用,如果不加則編譯器會(huì)自動(dòng)補(bǔ)齊。

          習(xí)題

          typedef struct

          {

          int a;//ARM(int=4)51(int=2)

          char b;// 1

          short c;// 2

          }AAA;

          typedef struct

          {

          char b;

          int a;

          short c;

          }BBB;

          i = sizeof(AAA);

          j = sizeof(BBB);

          //注意在51單片機(jī),ARM,PC不同

          51 (i=j=5)//好像強(qiáng)制單字節(jié)對齊

          ARM(i=8,j=12)//按規(guī)則默認(rèn)對齊

          PC(i=8,j=12)

          AAA對齊方式如下(ARM)

          I I I I

          I0I I

          BBB對齊方式如下(ARM)

          I0 0 0

          IIII

          I I0 0

          通過#pragma pack可以調(diào)整對齊字節(jié)數(shù)

          #pragma pack(1) //指定Align為 1字節(jié);

          。。。。。。。。。。。。//需要對齊的結(jié)構(gòu)體

          #pragma pack() //恢復(fù)到原先值



          關(guān)鍵詞: MDK對齊方

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();