專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機教程網(wǎng) >> MCU設(shè)計實例 >> 瀏覽文章

關(guān)于結(jié)構(gòu)體數(shù)據(jù)存儲的對齊問題

作者:龔平   來源:本站原創(chuàng)   點擊數(shù):  更新時間:2014年03月14日   【字體:
在C/C 中經(jīng)常需要進行存儲器的操作,關(guān)于數(shù)據(jù)如何在存儲器中存儲的問題也是非常重要的,如何在保證數(shù)據(jù)量(信息量)的同時又保證數(shù)據(jù)的存儲量最小,乍一聽感覺沒什么好討論的。但是作為學(xué)習(xí)嵌入式的必須要明白數(shù)據(jù)的存儲是與數(shù)據(jù)的結(jié)構(gòu)存在密切聯(lián)系的,特別是結(jié)構(gòu)體中的內(nèi)存分配問題。
 
首先應(yīng)該明白基本的類型在內(nèi)存中的大小,char型一般占有1個字節(jié),int型一般占有4個字節(jié),double型一般占有8個字節(jié),short 則占有2個字節(jié)(當(dāng)然也會存在一定的變化,具體情況依據(jù)編譯器決定)。我們都知道C語言的結(jié)構(gòu)體是一個不同類型數(shù)據(jù)的集合。那么一個結(jié)構(gòu)體到底占多少存儲空間呢?
 
首先應(yīng)該意識到C語言的存儲存在一定的特殊性。在C語言的結(jié)構(gòu)體中需要主要的是數(shù)據(jù)存儲的對齊方式。對齊主要是為了方便數(shù)據(jù)的訪問,提高計算機的處理速度,但是對齊會導(dǎo)致內(nèi)存空間的浪費,這些浪費對于大內(nèi)存空間的設(shè)備而言,沒什么必要,但是對于嵌入式系統(tǒng)而言會造成大量的浪費。
 
在32bits的系統(tǒng)中對一個寄存器(32bits)的訪問直接訪問,但是對于寄存器中某一個字節(jié)的訪問反而覺得很不方便,因此如果只是單個字節(jié)的訪問反而增加了系統(tǒng)的負擔(dān)。對一個寄存器的訪問可以通過一個起始地址來實現(xiàn),但是我們在很多CPU的用戶手冊中都會發(fā)現(xiàn),寄存器的起始地址都能被4整除,這就是為了提高計算速度而采取的一些默認的方式。一個寄存器一般而言占有4個bytes,那么對下一個寄存器的訪問只需要在原來的地址基礎(chǔ)上加上4個 bytes即可。
 
對齊的基本作用就是提高系統(tǒng)的功能,特別是訪問存儲器的能力得到提高。
 
對齊在使用中有較多的意義;镜氖褂迷瓌t:
1、對齊是為了提高系統(tǒng)的訪問速度,一般基本的對齊原則是按著最大的基本類型的長度進行對齊,較小的元素可以幾個組合起來填充一段對齊內(nèi)存,實現(xiàn)基本的對齊,但是需要滿足條件2。
2、結(jié)構(gòu)體中的元素也要滿足一定的分布條件,就是元素的存儲起始地址要滿足能夠整除該元素類型的長度。
3、在結(jié)構(gòu)體中存在結(jié)構(gòu)體的情況下,也只是按著結(jié)構(gòu)體中最大的基本類型長度對齊(包含內(nèi)部結(jié)構(gòu)體中的最大基本類型長度)。
 
在不同的編譯器之間也存在一定的差別。在linux中最大的對齊長度是 4個字節(jié),也就是如果結(jié)構(gòu)體中的最大的基本類型長度是大于4的,那么也按著4對齊,同時不會按著結(jié)構(gòu)體中最大的基本類型的長度對齊,伴隨著最大基本類型元素的起始地址也不再滿足能夠被最大元素類型長度對齊的原則,而是滿足整除4即可。但如果結(jié)構(gòu)體中最大的基本類型長度小于4,那么按著最大的基本類型長度對齊
但是在windows中基本上都是按著最大的基本類型長度進行對齊,和一般的原則相似。
 
這邊只是我的一些理解其中具體的要具體分析,在實際中建議將最大基本類型的元素放在開始的地方,然后將其他的數(shù)據(jù)按著一定的規(guī)律(能否組合起來滿足對齊條件等)定義結(jié)構(gòu)體,這個規(guī)律要根據(jù)實際情況分析。
 
下面通過基本的代碼進行演示:
  1. #include<stdio.h>
  2. #include<stdlib.h>
     

  3.  
  4. struct aa{
     
  5.     char a;
     
  6.     double b;
     
  7.     short c;
     
  8. };
     

  9.  
  10. struct bb
     
  11. {
     
  12.     double a;
     
  13.     short b;
     
  14.     char c;
     
  15. };
     

  16.  
  17. struct cc
     
  18. {
     
  19.     struct bb s1;
     
  20.     char s2;
     
  21. };
     

  22.  
  23. struct dd
     
  24. {
     
  25.     struct aa s1;
     
  26.     char s2;
     
  27. };
     

  28.  
  29. #pragma pack(1)
     
  30. struct ee
     
  31. {
     
  32.     double a;
     
  33.     short b;
     
  34.     char c;
     
  35. };
     

  36.  
  37. struct ff
     
  38. {
     
  39.     char a;
     
  40.     double b;
     
  41.     short c;
     
  42. };
     
  43. #pragma pack()
     

  44.  
  45. struct gg
     
  46. {
     
  47.     char a;
     
  48. };
     

  49.  
  50. struct jj
     
  51. {
     
  52.     char a;
     
  53.     short b;
     
  54. };
     

  55.  
  56. int main()
     
  57. {
     

  58.  
  59.     printf("double size is %d %d %d\n",sizeof(double),sizeof(short),sizeof(char));
     
  60.     printf("size of s1 = %d\nsize of s2 = %d\n",sizeof(struct aa),sizeof(struct bb));
     

  61.  
  62.     printf("size of t1 = %d\nsize of dd = %d\n",sizeof(struct cc),sizeof(struct dd));
     
  63.     
     
  64.     printf("size of struct ee = %d\nsize of struct ff = %d\nsize of struct gg = %d\nsize of struct jj = %d\n",
     
  65.         sizeof(struct ee),sizeof(struct ff),sizeof(struct gg),sizeof(struct jj));
     
  66.     exit(0);
     
  67. }
在linux下的結(jié)果:
 
 
在windows下的結(jié)果:
 
 
在linux下的存儲形式,其中黑色包圍起來的才是我們的存儲空間白色的部分是保留區(qū)域,通過下面的兩幅圖就可以知道其中的一些道理,知道其中所謂的完成一樣的功能,保證存儲空間最。
 
 
在windows下的存儲形式,其中黑色包圍起來的才是我們的存儲空間白色的部分是保留區(qū)域:
 
從上面的幾個圖片可以知道在C語言中的內(nèi)存分布是比較復(fù)雜的。一定要注意存儲的對齊形式,這樣才能了解其中的分布規(guī)律。當(dāng)然了上面的形式都只是在小端處理器模式下的存儲形式,對于大端也有類似的情況,只是存儲的位置不一樣,但是內(nèi)存的大小是相同的。
 
結(jié)構(gòu)體的定義不能是隨便的,如果考慮好對齊關(guān)系能夠節(jié)省大量的存儲空間。實現(xiàn)效率和存儲空間的折中。雖然#pragma pack(n)等能夠改變其中的對齊方式,不過建議不要隨便改動,可能得不償失。
關(guān)閉窗口

相關(guān)文章