文章來源 http://hi.baidu.com/colin719/blog/item/3f1783138e635f806538db40.html

位段以位為單位定義結(jié)構(gòu)體(或共用體)中成員所占存儲空間的長度。含有位段的結(jié)構(gòu)體類型稱為位段結(jié)構(gòu)。

位段結(jié)構(gòu)也是一種結(jié)構(gòu)體類型,只不過其中含有以位為單位定義存儲長度的整數(shù)類型位段成員。采用位段結(jié)構(gòu)既節(jié)省存儲空間,又可方便操作。

位段結(jié)構(gòu)中位段的定義格式為:
unsigned <成員名>:<二進(jìn)制位數(shù)>
例如:
struct bytedata
{unsigned a:2;   /*位段a,占2位*/
 unsigned:6;  /*無名位段,占6位,但不能訪問*/
 unsigned:0;     /*無名位段,占0位,表下一位段從下一字邊界開始*/
 unsigned b:10;  /*位段b,占10位*/
 int i;          /*成員i,從下一字邊界開始*/
}data;

位段數(shù)據(jù)的引用:
同結(jié)構(gòu)體成員中的數(shù)據(jù)引用一樣,但應(yīng)注意位段的最大取值范圍不要超出二進(jìn)制位數(shù)定的范圍,否則超出部分會丟棄。
例如:data.a=2;   但  data.a=10;就超出范圍(a占2位,最大3)

關(guān)于位段數(shù)據(jù),注意以下幾點(diǎn):

(1)一個位段必須存儲在同一存儲單元(即字)之中,不能跨兩個單元。如果其單元空間不夠,則剩余空間不用,從下一個單元起存放該位段。
(2)可以通過定義長度為0的位段的方式使下一位段從下一存儲單元開始。
(3)可以定義無名位段。
(4)位段的長度不能大于存儲單元的長度。
(5)位段無地址,不能對位段進(jìn)行取地址運(yùn)算。
(6)位段可以以%d,%o,%x格式輸出。
(7)位段若出現(xiàn)在表達(dá)式中,將被系統(tǒng)自動轉(zhuǎn)換成整數(shù)。

from  http://blog.csdn.net/junli0310/archive/2007/09/02/1769406.aspx

C語言中的結(jié)構(gòu)是有實(shí)現(xiàn)位段的能力的,噢!你問它到底是什么形式是吧?這個問題呆會給你答案。讓我們先看看位段的作用:位段是在字段的聲明后面加一個冒號以及一個表示字段位長的整數(shù)來實(shí)現(xiàn)的。這種用法又被就叫作“深入邏輯元件的編程”,如果你對系統(tǒng)編程感興趣,那么這篇文章你就不應(yīng)該錯過!
我把使用位段的幾個理由告訴大家:1、它能把長度為奇數(shù)的數(shù)據(jù)包裝在一起,從而節(jié)省存儲的空間;2、它可以很方便地訪問一個整型值的部分內(nèi)容。
首先我要提醒大家注意幾點(diǎn):1、位段成員只有三種類型:int ,unsigned int 和signed int這三種(當(dāng)然了,int型位段是不是可以取負(fù)數(shù)不是我說了算的,因?yàn)檫@是和你的編譯器來決定的。位段,位段,它是用來表示字段位長(bit)的,它只有整型值,不會有7.2這種float類型的,如果你說有,那你就等于承認(rèn)了有7.2個人這個概念,當(dāng)然也沒有char這個類型的);2、成員名后面的一個冒號和一個整數(shù),這個整數(shù)指定該位段的位長(bit);3、許多編譯器把位段成員的字長限制在一個int的長度范圍之內(nèi);4、位段成員在內(nèi)存的實(shí)現(xiàn)是從左到右還是從右到左是由編譯器來決定的,但二者皆對。
下面我們就來看看,它到底是什么東西(我先假定大家的機(jī)器字長為32位):
Struct WORD
{
unsigned int chara: 6:
unsigned int font : 7;
unsigned int maxsize : 19;
};
Struct WORD chone;
這一段是從我編寫的一個文字格式化軟件摘下來的,它最多可以容納64(既我說的unsigned int chara :6; 它總共是6位)個不同的字符值,可以處理128(既unsigned int font : 7 ;既2的7次方)種不同的字體,和2的19次方的單位長度的字。大家都可以看到maxsize是19位,它是無法被一個short int 類型的值所容納的,我們又可以看到其余的成員的長度比char還小,這就讓我們想起讓他們共享32位機(jī)器字長,這就避免用一個32位的整數(shù)來表示maxsize的位段。怎么樣?還要注意的是剛才的那一段代碼在16位字長的機(jī)器上是無法實(shí)現(xiàn)的,為什么?提醒你一下,看看上面提醒的第3點(diǎn),你會明白的!
你是不是發(fā)現(xiàn)這個東西沒有用啊?如果你點(diǎn)頭了,那你就錯了!這么偉大的創(chuàng)造怎么會沒有用呢(你對系統(tǒng)編程不感興趣,相信你會改變這么一個觀點(diǎn)的)?磁盤控制器大家應(yīng)該知道吧?軟驅(qū)與它的通信我們來看看是怎么實(shí)現(xiàn)的下面是一個磁盤控制器的寄存器:
│←5→│←5→│←9→│←8→│←1→│←1→∣←1→∣←1→∣←1→∣
上面位段從左到右依次代表的含義為:5位的命令,5位的扇區(qū),9位的磁道,8位的錯誤代碼,1位的HEAD LOADED,1位的寫保護(hù),1位的DISK SPINNING,1位的錯誤判斷符,還有1位的READY位。它要怎么來實(shí)現(xiàn)呢?你先自己寫寫看:
struct DISK_FORMAT
{
unsigned int command : 5;
unsigned sector : 5;
unsigned track : 9 ;
unsigned err_code : 8;
unsigned ishead_loaded : 1;
unsigned iswrit_protect : 1;
unsigned isdisk_spinning : 1;
unsigned iserr_ocur : 1;
undigned isready :1 ;
}; 
注:代碼中除了第一行使用了unsigned int 來聲明位段后就省去了int ,這是可行的,詳見ANCI C標(biāo)準(zhǔn)。
如果我們要對044c18bfH的地址進(jìn)行訪問的話,那就這樣:
#define DISK ((struct DISK_FORMAT *)0x044c18bf)
DISK->sector=fst_sector;
DISK->track=fst_track;
DISK->command=WRITE;
當(dāng)然那些都是要宏定義的哦!
我們用位段來實(shí)現(xiàn)這一目的是很方便的,其實(shí)這也可以用移位或屏蔽來實(shí)現(xiàn),你嘗試過就知道哪個更方便了!
我們今天的話題就到這兒,如果諸位還有疑問,可e-mail給我:arhuwen@163.com;
特別聲明哦:不要把以上內(nèi)容用于不法行為,否則后果自負(fù)。另外本文不可用于任何謀取商業(yè)利益的舉動,否則同上!


C編譯器對結(jié)構(gòu)空間缺省的分配
在C語言中,結(jié)構(gòu)是一種復(fù)合數(shù)據(jù)類型,其構(gòu)成元素既可以是基本數(shù)據(jù)類型(如int、long、float等)的變量,也可以是一些復(fù)合數(shù)據(jù)類型(如數(shù)組、結(jié)構(gòu)、聯(lián)合等等)的數(shù)據(jù)單元。在結(jié)構(gòu)中,編譯器為結(jié)構(gòu)的每個成員按其自然對界(alignment)條件分配空間;各個成員按照它們被聲明的順序在內(nèi)存中順序存儲,第一個成員的地址和整個結(jié)構(gòu)的地址相同。在缺省情況下,C編譯器為每一個變量或是數(shù)據(jù)單元按其自然對界條件分配空間,見表1:

        
表1:Win32下的自然對界條件
例如,下面的結(jié)構(gòu)各成員空間分配情況如圖1:
struct test {
char x1;
short x2;
float x3;
char x4;
};

圖1:缺省結(jié)構(gòu)空間分配
結(jié)構(gòu)的第一個成員x1,其偏移地址為0,占據(jù)了第1個字節(jié)。第二個成員x2為short類型,其起始地址必須2字節(jié)對界,因此,編譯器在x2和x1之間填充了一個空字節(jié)。結(jié)構(gòu)的第三個成員x3和第四個成員x4恰好落在其自然對界地址上,在它們前面不需要額外的填充字節(jié)。在test結(jié)構(gòu)中,成員x3要求4字節(jié)對界,是該結(jié)構(gòu)所有成員中要求的最大對界單元,因而test結(jié)構(gòu)的自然對界條件為4字節(jié),編譯器在成員x4后面填充了3個空字節(jié)。整個結(jié)構(gòu)所占據(jù)空間為12字節(jié)。

結(jié)構(gòu)中的位段
所謂位段是以位為單位定義長度的結(jié)構(gòu)體類型中的成員。編譯器對結(jié)構(gòu)中位段的分配遵從下面幾點(diǎn)原則:
? 對于長度為0的位段,其下一個位段從下一個存儲單元開始存放:
如:
struct T {
unsigned char a : 1;
unsigned char b : 2;
unsigned : 0;
unsigned c : 3;
};
結(jié)構(gòu)T的成員a和b在一個存儲單元中,c則在另一個存儲單元中。
? 一個位段必須存儲在同一存儲單元中,不能跨兩個單元:
如:
struct T {
unsigned char a : 4;
unsigned char b : 6;
};
結(jié)構(gòu)T的成員a在一個存儲單元中,b則在另一個存儲單元中。

更改C編譯器的缺省分配策略
一般地,可以通過下面的兩種方法改變?nèi)笔〉膶鐥l件:
? 使用偽指令#pragma pack ([n])
? 在編譯時使用命令行參數(shù)
#pragma pack ([n])偽指令允許你選擇編譯器為數(shù)據(jù)分配空間所采取的對界策略,見表2:

   
表2:更改缺省對界條件
在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結(jié)構(gòu)各成員的空間分配情況如圖2所示:


圖2:使用#pragma pack (1)后的結(jié)構(gòu)空間分配

應(yīng)用實(shí)例

  我們在日常編程工作中,特別是對一些網(wǎng)絡(luò)事務(wù)的處理,經(jīng)常會同其他人有著各種各樣的協(xié)議:如我傳給你20字節(jié)的頭,前4個字節(jié)表示……等等。很多人都是通過指針偏移的方法來得到各種信息,這樣做,不僅編程復(fù)雜,而且一旦協(xié)議有變化,程序修改起來也比較麻煩。在了解了編譯器對結(jié)構(gòu)空間的分配原則之后,我們完全可以利用這一特性定義自己的協(xié)議結(jié)構(gòu),通過訪問結(jié)構(gòu)的成員來獲取各種信息。這樣做,不僅簡化了編程,而且即使協(xié)議發(fā)生變化,我們也只需修改協(xié)議結(jié)構(gòu)的定義即可,其它程序無需修改,省時省力。下面以TCP協(xié)議首部為例,說明如何定義協(xié)議結(jié)構(gòu)。
TCP協(xié)議首部如圖3所示:


圖3:TCP首部
其協(xié)議結(jié)構(gòu)定義如下:
struct TCPHEADER {
short SrcPort; // 16位源端口號
short DstPort; // 16位目的端口號
int SerialNo; // 32位序列號
int AckNo; // 32位確認(rèn)號
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檢驗(yàn)和
short UrgentPointer; // 16位緊急指針
};
其協(xié)議結(jié)構(gòu)還可以定義為如下的形式:
struct TCPHEADER {
short SrcPort; // 16位源端口號
short DstPort; // 16位目的端口號
int SerialNo; // 32位序列號
int AckNo; // 32位確認(rèn)號
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檢驗(yàn)和
short UrgentPointer; // 16位緊急指針

本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/junli0310/archive/2007/09/02/1769406.aspx

fromhttp://hi.baidu.com/%B8%F8%EB%DE%CC%ED%CD%EB%B7%B9/blog/item/8ab4ae1f9d15fa0d304e15f4.html

1.什么是位段

在前面各章中, 我們已經(jīng)討論過字節(jié)概念了。在大多數(shù)的計算機(jī)系統(tǒng)中, 一個字節(jié)是由八個更小的, 稱作為位的單位組成的。位是比字節(jié)更小的單位。位只有兩個值, 1 或 0 。因此, 存儲在計算機(jī)存儲器中的一個字節(jié)可以看成由八個二進(jìn)制數(shù)字形成的串。

例如, 一個存放值 36 的字節(jié)是八個二進(jìn)制數(shù)字的串: 可以表示成 00100100。 存入值24 的字節(jié)可以表示成 00010100。

有時, 我們希望不僅對字節(jié)進(jìn)行操作, 也要能對位進(jìn)行操作。例如, 用布爾真或假條件表示的標(biāo)志, 在計算機(jī)中可用位來表示。

但是, 說明一個用作標(biāo)志的普通變量至少要用一個字節(jié)---8 位, 而在某些計算機(jī)系統(tǒng)中則可能是 16 位。 如果我們想在一個很大的表中存儲很多標(biāo)志, 那么 "被浪費(fèi)" 的內(nèi)存空間是很可觀的。在 C 語言中, 一種方法是用叫做位段的構(gòu)造類型來定義一個壓縮信息的結(jié)構(gòu)。

什么是位段呢? 位段是 C 語言特有的數(shù)據(jù)結(jié)構(gòu), 它允許我們定義一個由位組成的段, 并可為它賦以一個名字。



2.位段的用法

我們已經(jīng)了解什么是位段了, 現(xiàn)在我們繼續(xù)討論位段的使用方法。

先看一個例子: 我們需要用到五個變量。 假定, 其中三個用作標(biāo)志, 稱為 f1, f2 和 f3。
第四個稱為 type, 取值范圍為 1 至 12。 最后一個變量稱為 index, 值的范圍為 0 至 500。

通常, 我們用下面的語句來說明這些變量: 
char f1,f2,f3;
unsigned int type;
unsigned int index;

但是, 實(shí)際上標(biāo)志 f1, f2, f3 分別只需要 1 位。變量 type 只需要 4 位, 而變量 index 只需要 9 位。 總共是 16位 ---- 2 個字節(jié)。我們用兩個字節(jié)就夠了。

我們可這樣來做: 
struct packed_struct
{
    unsigned int f1 :1; 
    unsigned int f2 :1; 
    unsigned int f3 :1; 
    unsigned int type :4;
    unsigned int index :9;

};

該例中, 我們定義了一個結(jié)構(gòu) packed_struct。該結(jié)構(gòu)定義了五個成員

。第一個成員叫做 f1, 是 unsigned int 類型的。緊跟在該成員名之后的 :1 規(guī)定了它以 1 位存放。類似地, 標(biāo)志 f2 和 f3 被定義為長度只有 1 位的。定義成員 type 占有 4 位。定義成員 index 占有 9 位。C 編譯器自動地把上面的位段定義壓縮在一起。位段的劃分如圖所示。packed_struct 總共使用了 16 位。

這種方法的好處是, 定義成 packed_struct 類型的變量的位段, 可以如引用一般的結(jié)構(gòu)成員一樣方便地引用。同時, 使用了更少的內(nèi)存單元數(shù)。

我們已經(jīng)定義了一個稱作為 packed_struct 的包含著位段的結(jié)構(gòu)。現(xiàn)在, 我們象下面那樣定義一個稱作為 packet_data 的變量: struct packed_struct packed_data; 于是, 我們就可以用簡單的語句, 把 packed_data 的 type 位段設(shè)置為 7: 
packed_data.type = 7; 類似地, 我們可以用下面的語句把這個位段的值設(shè)為 n: 
packed_data.type = n; 我們不必?fù)?dān)心 n 的值太長, 以致不能放入 type 位段中, C 編譯器會自動地僅取出 n 的低四位, 把它賦值給 packed_data.type。取出位段的值也自動地處理的, 因此語句 n = packed_data.type; 將從 packed_data 中取出 type 位段, 并把它的值賦給 n。

在一般的表達(dá)式中可以使用位段, 此時, 位段自動地轉(zhuǎn)換成整數(shù)。因此, 表達(dá)式 
i = packed_data.index/5+1; 是完全有效的。

在包含位段的結(jié)構(gòu)中, 也可以包括 "通常的" 數(shù)據(jù)類型。因此, 如果我們想定義一個結(jié)構(gòu), 它包含一個 int, 一個 char, 和二個 1 位的標(biāo)志, 那么, 下面的定義是有效的: 
struct table_entry
{
    int     count ;
    char     c;
    unsigned int f1 :1;
    unsigned int f2 :1;
};


當(dāng)位段出現(xiàn)在結(jié)構(gòu)定義中時, 它們就被壓縮成字。如果某個位段無法放入一個字中, 那么該字的剩余部分跳過不用, 該位段被放入下一個字中。

使用位段時, 必須注意下列事項:

  • 在某些機(jī)器上, 位段總是作為 unsigned 處理, 而不管它們是否被說明成 unsigned 的。
  • 大多數(shù)C 編譯器都不支持超過一個字長的位段。
  • 位段不可標(biāo)明維數(shù); 即, 不能說明位段數(shù)組, 例如 flag:l[2]。
  • 最后, 不可以取位段地址。原因是, 在這種情況不, 顯然沒有稱作為 "位段指針" 類型的變量。

                                                                                  

這里, 我們再深入討論一下位段。如果使用下面的結(jié)構(gòu)定義:

struct bits
{
    unsigned int f1:1;
    int     word;
    unsigned int f3:1;
};

那么, 位段是怎樣壓縮的呢? 由于成員 word 出現(xiàn)于其間, 故 f1, f3 不會壓縮在同一個字內(nèi)。C 編譯器不會重新安排位段定義來試圖優(yōu)化存儲空間。

可以指定無名位段, 使得一個字中的某些位被 "跳過"。因此, 定義:
struct x_entry
{
    unsigned int type :4;
    unsigned int :3;
    unsigned int count :9;
};

將定義一個結(jié)構(gòu) x_entry, 它包含兩個位段變量 type 和 count, 而無名位段規(guī)定了 type 和 count 間隔三位。

來自:http://its.nbtvu.net.cn/xhyu/cai_c/c_web/c/c8/c83.htm

http://www.cnblogs.com/jincwfly/archive/2007/09/14/892341.html

關(guān)于結(jié)構(gòu)體內(nèi)存對齊

內(nèi)存對齊”應(yīng)該是編譯器的“管轄范圍”。編譯器為程序中的每個“數(shù)據(jù)單元”安排在適當(dāng)?shù)奈恢蒙稀5荂語言的一個特點(diǎn)就是太靈活,太強(qiáng)大,它允許你干預(yù)“內(nèi)存對齊”。如果你想了解更加底層的秘密,“內(nèi)存對齊”對你就不應(yīng)該再透明了。

一、內(nèi)存對齊的原因
大部分的參考資料都是如是說的:
1、平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數(shù)據(jù)的;某些硬件平臺只能在某些地址處取某些特定類型的數(shù)據(jù),否則拋出硬件異常。
2、性能原因:數(shù)據(jù)結(jié)構(gòu)(尤其是棧)應(yīng)該盡可能地在自然邊界上對齊。原因在于,為了訪問未對齊的內(nèi)存,處理器需要作兩次內(nèi)存訪問;而對齊的內(nèi)存訪問僅需要一次訪問。

二、對齊規(guī)則
每個特定平臺上的編譯器都有自己的默認(rèn)“對齊系數(shù)”(也叫對齊模數(shù))。程序員可以通過預(yù)編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一系數(shù),其中的n就是你要指定的“對齊系數(shù)”。

對齊步驟:
1、數(shù)據(jù)成員對齊規(guī)則:結(jié)構(gòu)(struct)(或聯(lián)合(union))的數(shù)據(jù)成員,第一個數(shù)據(jù)成員放在offset為0的地方,以后每個數(shù)據(jù)成員的對齊按照#pragma pack指定的數(shù)值和這個數(shù)據(jù)成員自身長度中,比較小的那個進(jìn)行。
2、結(jié)構(gòu)(或聯(lián)合)的整體對齊規(guī)則:在數(shù)據(jù)成員完成各自對齊之后,結(jié)構(gòu)(或聯(lián)合)本身也要進(jìn)行對齊,對齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)(或聯(lián)合)最大數(shù)據(jù)成員長度中,比較小的那個進(jìn)行。
3、結(jié)合1、2顆推斷:當(dāng)#pragma pack的n值等于或超過所有數(shù)據(jù)成員長度的時候,這個n值的大小將不產(chǎn)生任何效果。
備注:數(shù)組成員按長度按數(shù)組類型長度計算,如char t[9],在第1步中數(shù)據(jù)自身長度按1算,累加結(jié)構(gòu)體時長度為9;第2步中,找最大數(shù)據(jù)長度時,如果結(jié)構(gòu)體T有復(fù)雜類型成員A的,該A成員的長度為該復(fù)雜類型成員A的最大成員長度。

三、試驗(yàn)
我們通過一系列例子的詳細(xì)說明來證明這個規(guī)則吧!
我試驗(yàn)用的編譯器包括GCC 3.4.2和VC6.0的C編譯器,平臺為Windows XP + Sp2。

我們將用典型的struct對齊來說明。首先我們定義一個struct:
#pragma pack(n) /* n = 1, 2, 4, 8, 16 */
struct test_t {
 int a;
 char b;
 short c;
 char d;
};
#pragma pack(n)
首先我們首先確認(rèn)在試驗(yàn)平臺上的各個類型的size,經(jīng)驗(yàn)證兩個編譯器的輸出均為:
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4

我們的試驗(yàn)過程如下:通過#pragma pack(n)改變“對齊系數(shù)”,然后察看sizeof(struct test_t)的值。

1、1字節(jié)對齊(#pragma pack(1))
輸出結(jié)果:sizeof(struct test_t) = 8 [兩個編譯器輸出一致]
分析過程:
1) 成員數(shù)據(jù)對齊
#pragma pack(1)
struct test_t {
 int a;  /* 長度4 < 1 按1對齊;起始o(jì)ffset=0 0%1=0;存放位置區(qū)間[0,3] */
 char b;  /* 長度1 = 1 按1對齊;起始o(jì)ffset=4 4%1=0;存放位置區(qū)間[4] */
 short c; /* 長度2 > 1 按1對齊;起始o(jì)ffset=5 5%1=0;存放位置區(qū)間[5,6] */
 char d;  /* 長度1 = 1 按1對齊;起始o(jì)ffset=7 7%1=0;存放位置區(qū)間[7] */
};
#pragma pack()
成員總大小=8

2) 整體對齊
整體對齊系數(shù) = min((max(int,short,char), 1) = 1
整體大小(size)=$(成員總大小) 按 $(整體對齊系數(shù)) 圓整 = 8 /* 8%1=0 */ [注1]

2、2字節(jié)對齊(#pragma pack(2))
輸出結(jié)果:sizeof(struct test_t) = 10 [兩個編譯器輸出一致]
分析過程:
1) 成員數(shù)據(jù)對齊
#pragma pack(2)
struct test_t {
 int a;  /* 長度4 > 2 按2對齊;起始o(jì)ffset=0 0%2=0;存放位置區(qū)間[0,3] */
 char b;  /* 長度1 < 2 按1對齊;起始o(jì)ffset=4 4%1=0;存放位置區(qū)間[4] */
 short c; /* 長度2 = 2 按2對齊;起始o(jì)ffset=6 6%2=0;存放位置區(qū)間[6,7] */
 char d;  /* 長度1 < 2 按1對齊;起始o(jì)ffset=8 8%1=0;存放位置區(qū)間[8] */
};
#pragma pack()
成員總大小=9

2) 整體對齊
整體對齊系數(shù) = min((max(int,short,char), 2) = 2
整體大小(size)=$(成員總大小) 按 $(整體對齊系數(shù)) 圓整 = 10 /* 10%2=0 */

3、4字節(jié)對齊(#pragma pack(4))
輸出結(jié)果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
分析過程:
1) 成員數(shù)據(jù)對齊
#pragma pack(4)
struct test_t {
 int a;  /* 長度4 = 4 按4對齊;起始o(jì)ffset=0 0%4=0;存放位置區(qū)間[0,3] */
 char b;  /* 長度1 < 4 按1對齊;起始o(jì)ffset=4 4%1=0;存放位置區(qū)間[4] */
 short c; /* 長度2 < 4 按2對齊;起始o(jì)ffset=6 6%2=0;存放位置區(qū)間[6,7] */
 char d;  /* 長度1 < 4 按1對齊;起始o(jì)ffset=8 8%1=0;存放位置區(qū)間[8] */
};
#pragma pack()
成員總大小=9

2) 整體對齊
整體對齊系數(shù) = min((max(int,short,char), 4) = 4
整體大小(size)=$(成員總大小) 按 $(整體對齊系數(shù)) 圓整 = 12 /* 12%4=0 */

4、8字節(jié)對齊(#pragma pack(8))
輸出結(jié)果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
分析過程:
1) 成員數(shù)據(jù)對齊
#pragma pack(8)
struct test_t {
 int a;  /* 長度4 < 8 按4對齊;起始o(jì)ffset=0 0%4=0;存放位置區(qū)間[0,3] */
 char b;  /* 長度1 < 8 按1對齊;起始o(jì)ffset=4 4%1=0;存放位置區(qū)間[4] */
 short c; /* 長度2 < 8 按2對齊;起始o(jì)ffset=6 6%2=0;存放位置區(qū)間[6,7] */
 char d;  /* 長度1 < 8 按1對齊;起始o(jì)ffset=8 8%1=0;存放位置區(qū)間[8] */
};
#pragma pack()
成員總大小=9

2) 整體對齊
整體對齊系數(shù) = min((max(int,short,char), 8) = 4
整體大小(size)=$(成員總大小) 按 $(整體對齊系數(shù)) 圓整 = 12 /* 12%4=0 */


5、16字節(jié)對齊(#pragma pack(16))
輸出結(jié)果:sizeof(struct test_t) = 12 [兩個編譯器輸出一致]
分析過程:
1) 成員數(shù)據(jù)對齊
#pragma pack(16)
struct test_t {
 int a;  /* 長度4 < 16 按4對齊;起始o(jì)ffset=0 0%4=0;存放位置區(qū)間[0,3] */
 char b;  /* 長度1 < 16 按1對齊;起始o(jì)ffset=4 4%1=0;存放位置區(qū)間[4] */
 short c; /* 長度2 < 16 按2對齊;起始o(jì)ffset=6 6%2=0;存放位置區(qū)間[6,7] */
 char d;  /* 長度1 < 16 按1對齊;起始o(jì)ffset=8 8%1=0;存放位置區(qū)間[8] */
};
#pragma pack()
成員總大小=9

2) 整體對齊
整體對齊系數(shù) = min((max(int,short,char), 16) = 4
整體大小(size)=$(成員總大小) 按 $(整體對齊系數(shù)) 圓整 = 12 /* 12%4=0 */

(colin719)