C實例編程:C編譯器對結構空間的分配及其應用

字號:

c編譯器對結構空間缺省的分配
    在c語言中,結構是一種復合數(shù)據(jù)類型,其構成元素既可以是基本數(shù)據(jù)類型(如int、long、float等)的變量,也可以是一些復合數(shù)據(jù)類型(如數(shù)組、結構、聯(lián)合等等)的數(shù)據(jù)單元。在結構中,編譯器為結構的每個成員按其自然對界(alignment)條件分配空間;各個成員按照它們被聲明的順序在內(nèi)存中順序存儲,第一個成員的地址和整個結構的地址相同。在缺省情況下,c編譯器為每一個變量或是數(shù)據(jù)單元按其自然對界條件分配空間
    例如,下面的結構各成員空間分配情況:
    struct test {
    char x1;
    short x2;
    float x3;
    char x4;
    };
    結構的第一個成員x1,其偏移地址為0,占據(jù)了第1個字節(jié)。第二個成員x2為short類型,其起始地址必須2字節(jié)對界,因此,編譯器在x2和x1之間填充了一個空字節(jié)。結構的第三個成員x3和第四個成員x4恰好落在其自然對界地址上,在它們前面不需要額外的填充字節(jié)。在test結構中,成員x3要求4字節(jié)對界,是該結構所有成員中要求的對界單元,因而test結構的自然對界條件為4字節(jié),編譯器在成員x4后面填充了3個空字節(jié)。整個結構所占據(jù)空間為12字節(jié)。
    結構中的位段
    所謂位段是以位為單位定義長度的結構體類型中的成員。編譯器對結構中位段的分配遵從下面幾點原則:
    ? 對于長度為0的位段,其下一個位段從下一個存儲單元開始存放:
    如:
    struct t {
    unsigned char a : 1;
    unsigned char b : 2;
    unsigned : 0;
    unsigned c : 3;
    };
    結構t的成員a和b在一個存儲單元中,c則在另一個存儲單元中。
    · 一個位段必須存儲在同一存儲單元中,不能跨兩個單元:
    如:
    struct t {
    unsigned char a : 4;
    unsigned char b : 6;
    };
    結構t的成員a在一個存儲單元中,b則在另一個存儲單元中。
    更改c編譯器的缺省分配策略
    一般地,可以通過下面的兩種方法改變?nèi)笔〉膶鐥l件:
    · 使用偽指令#pragma pack ([n])
    · 在編譯時使用命令行參數(shù)
    #pragma pack ([n])偽指令允許你選擇編譯器為數(shù)據(jù)分配空間所采取的對界策略.
    在microsfot visual c++中,命令行參數(shù)/zp[n]可以改變?nèi)笔鐥l件;在borland c++ builder中,命令行參數(shù)-a[n]可以改變?nèi)笔鐥l件。n的含義和#pragma pack中的n相同。
    例如,在使用了#pragma pack (1)偽指令后,test結構各成員的空間分配情況.
    應用實例
    我們在日常編程工作中,特別是對一些網(wǎng)絡事務的處理,經(jīng)常會同其他人有著各種各樣的協(xié)議:如我傳給你20字節(jié)的頭,前4個字節(jié)表示……等等。很多人都是通過指針偏移的方法來得到各種信息,這樣做,不僅編程復雜,而且一旦協(xié)議有變化,程序修改起來也比較麻煩。在了解了編譯器對結構空間的分配原則之后,我們完全可以利用這一特性定義自己的協(xié)議結構,通過訪問結構的成員來獲取各種信息。這樣做,不僅簡化了編程,而且即使協(xié)議發(fā)生變化,我們也只需修改協(xié)議結構的定義即可,其它程序無需修改,省時省力。下面以tcp協(xié)議首部為例,說明如何定義協(xié)議結構。
    其協(xié)議結構定義如下:
    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位緊急指針
    };
    其協(xié)議結構還可以定義為如下的形式:
    struct tcpheader {
    short srcport; // 16位源端口號
    short dstport; // 16位目的端口號
    int serialno; // 32位序列號
    int ackno; // 32位確認號
    unsigned char haderlen : 4; // 4位首部長度
    unsigned char : 0; // 保留6位中的4位
    unsigned char reserved : 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位緊急指針
    }