天天看點

收藏, 以防忘了

在c語言中,結構是一種複合資料類型,其構成元素既可以是基本資料類型(如int、long、float等)的變量,也可以是一些複合資料類型(如數組、結構、聯合等)的資料單元。在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件配置設定空間。各個成員按照它們被聲明的順序在記憶體中順序存儲,第一個成員的位址和整個結構的位址相同。

     例如,下面的結構各成員空間配置設定情況:

struct test

{

     char x1;

     short x2;

     float x3;

     char x4;

};

     結構的第一個成員x1,其偏移位址為0,占據了第1個位元組。第二個成員x2為short類型,其起始位址必須2位元組對界,是以,編譯器在x2和x1之間填充了一個空位元組。結構的第三個成員x3和第四個成員x4恰好落在其自然對界位址上,在它們前面不需要額外的填充位元組。在test結構中,成員x3要求4位元組對界,是該結構所有成員中要求的最大對界單元,因而test結構的自然對界條件為4位元組,編譯器在成員x4後面填充了3個空位元組。整個結構所占據空間為12位元組。更改c編譯器的預設位元組對齊方式

     在預設情況下,c編譯器為每一個變量或是資料單元按其自然對界條件配置設定空間。一般地,可以通過下面的方法來改變預設的對界條件:

  · 使用僞指令#pragma pack (n),c編譯器将按照n個位元組對齊。

     · 使用僞指令#pragma pack (),取消自定義位元組對齊方式。

     另外,還有如下的一種方式:

     · __attribute((aligned (n))),讓所作用的結構成員對齊在n位元組自然邊界上。如果結構中有成員的長度大于n,則按照最大成員的長度來對齊。

     · __attribute__ ((packed)),取消結構在編譯過程中的優化對齊,按照實際占用位元組數進行對齊。

以上的n = 1, 2, 4, 8, 16... 第一種方式較為常見。

應用執行個體

  在網絡協定程式設計中,經常會處理不同協定的資料封包。一種方法是通過指針偏移的方法來得到各種資訊,但這樣做不僅程式設計複雜,而且一旦協定有變化,程式修改起來也比較麻煩。在了解了編譯器對結構空間的配置設定原則之後,我們完全可以利用這一特性定義自己的協定結構,通過通路結構的成員來擷取各種資訊。這樣做,不僅簡化了程式設計,而且即使協定發生變化,我們也隻需修改協定結構的定義即可,其它程式無需修改,省時省力。下面以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() // 取消1位元組對齊方式