#pragma pack 詳解

#pragma pack(push,1)與#pragma pack(1)的區別

這是給編譯器用的參數設置(注意,在編譯階段),有關結構體字節對齊方式設置, #pragma pack是指定數據在內存中的對齊方式。

#pragma pack (n)             //作用:C編譯器將按照n個字節對齊。
#pragma pack ()              // 作用:取消自定義字節對齊方式。


#pragma  pack (push,1)     //作用:是指把原來對齊方式設置壓棧,並設新的對齊方式設置爲1個字節對齊
#pragma pack(pop)           // 作用:恢復對齊狀態

因此可見,加入push和pop可以使對齊恢復到原來狀態,而不是編譯器默認,可以說後者更優,但是很多時候兩者差別不大。

如果#pramga pack(n)中的n大於結構體成員中任何一個成員所佔用的字節數,則該n值無效。編譯器會選取結構體中最大數據成員的字節數爲基準進行對齊。

 

結構體爲什麼默認對齊

在沒有設置多少字節對齊的時候,結構體會默認選取結構體中最大數據成員的字節數爲基礎進行對齊。編譯器爲什麼會耗費資源呢?

對齊的作用和原因:各個硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。比如有些架構的CPU在訪問 一個沒有進行對齊的變量的時候會發生錯誤,那麼在這種架構下編程必須保證字節對齊.其他平臺可能沒有這種情況,但是最常見的是如果不按照適合其平臺要求對 數據存放進行對齊,會在存取效率上帶來損失。比如有些平臺每次讀都是從偶地址開始,如果一個int型(假設爲32位系統)如果存放在偶地址開始的地方,那 麼一個讀週期就可以讀出這32bit,而如果存放在奇地址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低字節進行拼湊才能得到該32bit數 據。顯然在讀取效率上下降很多。另外一層原因是:某些硬件平臺只能從規定的地址處取某些特定類型的數據,否則會拋出硬件異常。

爲什麼使用#pragma pack

上面說了那麼多了,人家結構體會採用默認的對齊方式,以空間換取CPU的讀取效率,那爲啥我們還要去修改其對齊方式呢?

原因是:一節省空間,二在某些場合使結構體更易於控制。

應用實例:

在網絡協議編程中,經常會處理不同協議的數據報文。一種方法是通過指針偏移的方法來得到各種信息,但這樣做不僅編程複雜,而且一旦協議有變化,程序修改起來也比較麻煩。在瞭解了編譯器對結構空間的分配原則之後,我們完全可以利用這一特性定義自己的協議結構,通過訪問結構的成員來獲取各種信息。這樣做,不僅簡化了編程,而且即使協議發生變化,我們也只需修改協議結構的定義即可,其它程序無需修改,省時省力。下面以TCP協議首部爲例,說明如何定義協議結構。其協議結構定義如下:

#pragma pack(1) // 按照1字節方式進行對齊
struct TCPHEADER 
{
     short SrcPort; // 16位源端口號
     short DstPort; // 16位目的端口號
     int SerialNo; // 32位序列號
     int AckNo; // 32位確認號
     unsigned char HaderLen : 4; // 4位首部長度
     unsigned char Reserved1 : 4; // 保留6位中的4位
     unsigned char Reserved2 : 2; // 保留6位中的2位
     unsigned char URG : 1;
     unsigned char ACK : 1;
     unsigned char PSH : 1;
     unsigned char RST : 1;
     unsigned char SYN : 1;
     unsigned char FIN : 1;
     short WindowSize; // 16位窗口大小
     short TcpChkSum; // 16位TCP檢驗和
     short UrgentPointer; // 16位緊急指針
}; 
#pragma pack()

有關位域的使用請參考https://blog.csdn.net/u010977122/article/details/89240784

 

以下是C/C++中不同數據類型所佔用的內存的大小:

類型 32系統位(字節) 64位系統(字節)
char 1 1
int 4 大多數4,少數8
short 2 2
long 4 8
float 4 4
double 8 8
指針 4 8
結構體(struct) 對齊問題 對齊問題
聯合體(union) 成員中最長的成員 成員中最長的成員
枚舉(enum) 根據數據類型 根據數據類型

所以想判斷當前系統是多少位的,最簡單的做法就是看看指針佔用幾個字節。

發佈了46 篇原創文章 · 獲贊 75 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章