資料對齊
我們在進行定義資料結構計算資料結構大小的時候,或者進行網路通訊的socket傳送資料的時候,都會遇到一個共同的問題:資料對齊問題。
這個問題是硬體為提高訪問資料的效率,引出的問題,這裡就不具體說這樣為什麼可以提高資料的訪問效率,有興趣的人,網上都有。
既然這個問題是實實在在存在的,並且軟體發展了這麼多年,也肯定有破解之道,下面就簡單的介紹常見的3種方法:
1. 手動對齊,根據自己定義的資料結構,然後根據大小,按照一定的規律去排兵佈陣,就可以讓資料結構緊湊,儘量少的出現記憶體空隙。
這種方法實際上就是要求我們有一個好的程式設計習慣,這樣可以提高我們程式碼的整潔性,也可以節省記憶體空間
2. 使用#pragam pack(n) 對齊資料結構
這條預處理指令中的n就是按照那個位元組進行對齊,n=1~4 並且必須是2的倍數
當n=4的時候,就是我們預設的資料結構對齊方式
當n=1的時候,也就是最節省空間的方法
以前受硬體條件的限制,我們能減少記憶體的佔用就儘量少的佔用記憶體,才會這樣去做,不過現在的儲存晶片,動輒上G,甚至上T,比以前的K級別的晶片容量打多了。
3. 使用 __attribute__ ((packed)) ,讓編譯器取消結構在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊,這樣子兩邊都需要使用 __attribute__ ((packed))取消優化對齊,就不會出現對齊的錯位現象。
這種方式與上邊的第二種方式是相同的
針對這個問題,個人覺得已經沒有什麼好研究的了,存在就存在,我們的硬體太大了,畢竟不是新中國剛成立時期,卻記憶體。如果確實想了解一下或者有強迫症的人,可以繼續看下邊關於attribute的一些使用規則,語法。
關於attribute的使用規則 來源於網上:
1. __attribute__ ((packed)) 的作用就是告訴編譯器取消結構在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊,是GCC特有的語法。這個功能是跟作業系統沒關係,跟編譯器有關,gcc編譯器不是緊湊模式的,我在windows下,用vc的編譯器也不是緊湊的,用tc的編譯器就是緊湊的。例如:
在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(緊湊模式)
在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非緊湊模式)
在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5
2. __attribute__關鍵字主要是用來在函式或資料宣告中設定其屬性。給函式賦給屬性的主要目的在於讓編譯器進行優化。函式宣告中的__attribute__((noreturn)),就是告訴編譯器這個函式不會返回給呼叫者,以便編譯器在優化時去掉不必要的函式返回程式碼。
GNU C的一大特色就是__attribute__機制。__attribute__可以設定函式屬性(Function Attribute)、變數屬性(Variable Attribute)和型別屬性(Type Attribute)。
__attribute__書寫特徵是:__attribute__前後都有兩個下劃線,並且後面會緊跟一對括弧,括弧裡面是相應的__attribute__引數。
__attribute__語法格式為:
__attribute__ ((attribute-list))
其位置約束:放於宣告的尾部“;”之前。
函式屬性(Function Attribute):函式屬性可以幫助開發者把一些特性新增到函式宣告中,從而可以使編譯器在錯誤檢查方面的功能更強大。__attribute__機制也很容易同非GNU應用程式做到相容之功效。
GNU CC需要使用 –Wall編譯器來擊活該功能,這是控制警告資訊的一個很好的方式。
packed屬性:使用該屬性可以使得變數或者結構體成員使用最小的對齊方式,即對變數是一位元組對齊,對域(field)是位對齊。
如果你看過GPSR協議在TinyOS中的實現,你一定會注意到下面的語句:
- typedef struct {
- double x;
- double y;
- } __attribute__((packed)) position_t;
開始我們還可以理解,不久是定義一個結構體嘛!不過看到後面的語句,你可能就會一頭霧水了,’ __attribute__((packed))’是什麼東西?有什麼作用?一連串的疑問馬上就會從你腦袋裡冒出來。雖然這個對理解整個程式沒有什麼影響,但我不想讓這些疑問一直呆在我的腦子裡,負擔太重。省得以後念念不忘,而且也許有一天可以用的上呢。搞清楚這個問題吧!
GNU C的一大特色(卻不被初學者所知)就是__attribute__機制。__attribute__可以設定函式屬性(Function Attribute)、變數屬性(Variable Attribute)和型別屬性(Type Attribute)。
__attribute__語法格式為:
__attribute__ ((attribute-list))
其位置約束為:放於宣告的尾部“;”之前。
packed是型別屬性(Type Attribute)的一個引數,使用packed可以減小物件佔用的空間。需要注意的是,attribute屬性的效力與你的聯結器也有關,如果你的聯結器最大隻支援16位元組對齊,那麼你此時定義32位元組對齊也是無濟於事的。
使用該屬性對struct或者union型別進行定義,設定其型別的每一個變數的記憶體約束。當用在enum型別定義時,暗示了應該使用最小完整的型別(it indicates that the smallest integral type should be used)。
下面的例子中,my-packed-struct型別的變數陣列中的值會緊湊在一起,但內部的成員變數s不會被“pack”,如果希望內部的成員變數也被packed的話,my-unpacked-struct也需要使用packed進行相應的約束。