1. 程式人生 > >C語言之#pragma pack或者__packed學習

C語言之#pragma pack或者__packed學習

C語言之#pragma pack學習

轉自:http://www.cppblog.com/range/archive/2011/07/15/151094.html

      最近除錯網路的服務端程式,自己寫了一個小客戶端程式來測試,發現服務程式解包錯誤。經除錯發現客戶端的協議頭大小和伺服器端的協議頭大小不一致。原因是伺服器端加了#pragma pack(1),而客戶端沒加。

    之前沒接觸過這個編譯巨集,現在來認真學習之。

    首先google之~~

    原來#pragma pack有幾種形式,我所接觸到的是#pragma pack(n),即變數以n位元組對齊。

    變數對齊在每個系統中是不一樣的,預設的對齊方式能有效的提高cpu取指取數的速度,但是可能會浪費一定的空間。在網路程式中採用#pragma pack(1),即變數緊縮,不但可以減少網路流量,還可以相容各種系統,不會因為系統對齊方式不同而導致解包錯誤。

    瞭解了概念和優點,現在我們就來測試之~

    平臺:CPU—Pentium E5700 記憶體—2G

     1.作業系統:ubuntu 11.04 32bit   編譯器:G++ 4.5.2

     2.作業系統:windows xp              編譯器:VS2010

    先看第一個測試。

    結構體在正常情況和緊縮情況在以上不同環境下佔用的記憶體大小。

1 struct pack { 2   int i; 3   short s; 4   double d; 5   char c; 6   short f; 7 }

      測試結果為:

    1:    

    2:             測試結果分析:

    可以看出緊縮後結構體的大小為15,是結構體內建型別大小的和。但是在預設情況下,結構體的大小都是對齊位元組數的倍數。ubuntu下pack只需要20個位元組,而windows要24個位元組。這是因為ubuntu是以4位元組對齊,而windows則是以最大的內建型別的位元組數對齊,在結構體內最大的內建型別為double,其大小為8個位元組。他們在記憶體中的對齊方式如下圖:

    1:

    

    2:

    

   還需注意的是,在對齊型別的內部都是以2位元組對齊的。

   結論:在預設情況下,linux作業系統是以4位元組對齊,windows作業系統則是以最大的內建型別對齊。

   第二個測試

   一個結構體內包含另外一個結構體,其大小的情況。

   內部的結構體為

1 struct pack { 2   short s; 3   double d; 4 }

   外部的結構體為

   1 struct complex _pack{

2   char c; 3   struct pack s; 4   double d; 5 };

    我們有四種情況:

     1.      pack緊縮,complex _pack緊縮

     2.      pack緊縮,complex _pack預設

     3.      pack預設,complex _pack緊縮

     4.      pack預設,complex _pack預設

    以下的排列均按此順序。

     測試的結果

      1:

      

     2:

      

    測試結果分析:

    在兩個作業系統下,除了第一種情況----內結構體和外結構體都緊縮----相同之外,其他三種情況都不相同。我們可以根據偏移畫出結構體在記憶體中的情況。第一種情況省略。

     1:

     

     2:

     

    結論:#pragma pack隻影響當前結構體的變數的對齊情況,並不會影響結構體內部的結構體變數的排列情況。或者說#pragma pack的作用域只是一層。我們由第三種情況,內部結構體正常,外部結構體緊縮,可以得出結構體的對齊是按偏移計算的。

    這裡還有一個問題沒解決,為什麼第二種情況內部結構體的偏移都是1?不是4或者8?