深入探索struct的巧妙用法
掃描二維碼
隨時(shí)隨地手機(jī)看文章
struct的作用
一般來(lái)說(shuō),區(qū)別一個(gè)開發(fā)人員是否具備豐富開發(fā)經(jīng)歷的標(biāo)志在于其會(huì)不會(huì)使用struct,怎么使用strcut。
在網(wǎng)絡(luò)協(xié)議、通信控制、嵌入式系統(tǒng)的編程中,我們經(jīng)常要傳送的不是簡(jiǎn)單的字節(jié)流(char型數(shù)組),而是多種數(shù)據(jù)組合起來(lái)的一個(gè)整體,其表現(xiàn)形式是一個(gè)結(jié)構(gòu)體。
初級(jí)的開發(fā)人員往往將所有需要傳送的內(nèi)容依順序保存在char 型數(shù)組中,通過指針偏移的方法傳送網(wǎng)絡(luò)報(bào)文等信息。這樣做編程復(fù)雜,易出錯(cuò),而且一旦控制方式及通信協(xié)議有所變化,程序就要進(jìn)行非常細(xì)致的修改。
一個(gè)有經(jīng)驗(yàn)的開發(fā)者則靈活運(yùn)用結(jié)構(gòu)體,舉一個(gè)例子,假設(shè)網(wǎng)絡(luò)或控制協(xié)議中需要傳送三種報(bào)文,其格式分別為packetA、packetB、packetC
typedef struct StructA { int a; char b; } A; typedef struct StructB { chara; shortb; } B; typedef struct StructC { int a; char b; float c; } C;
報(bào)文結(jié)構(gòu)設(shè)計(jì)
typedef enum PacketType{ PacketTypeA = 1, PacketTypeB, PacketTypeC }; struct CommuPacket { PacketType type; ////< 報(bào)文類型 union { ////< 每次傳輸?shù)氖瞧渲械囊环N,因此使用union A packet_a; B packet_b; C packet_c; } };
報(bào)文傳輸設(shè)計(jì)
/* pSendData 發(fā)送字節(jié)流的首地址 len 發(fā)送數(shù)據(jù)長(zhǎng)度 */ void Send(char *pSendData, unsigned int len); /* pRecvData 接收緩沖區(qū)首地址 len 接受長(zhǎng)度 返回值:實(shí)際接收長(zhǎng)度 */ unsigned int Recv(char *pRecvData, unsigned int len);
判斷報(bào)文類型,并作相應(yīng)處理
switch(type) { case PacketTypeA : ... break; case PacketTypeB : ... break; case PacketTypeC : ... break; }
struct成員對(duì)齊
自然對(duì)齊
struct 是一種復(fù)合數(shù)據(jù)類型,其構(gòu)成元素既可以是基本數(shù)據(jù)類型(如int、long、float 等)的變量,也可以是一些復(fù)合數(shù)據(jù)類型(如array、struct、union 等)的數(shù)據(jù)單元。對(duì)于結(jié)構(gòu)體,編譯器會(huì)自動(dòng)進(jìn)行成員變量的對(duì)齊,以提高運(yùn)算效率。缺省情況下,編譯器為結(jié)構(gòu)體的每個(gè)成員按其自然對(duì)界(natural alignment)條件分配空間。各個(gè)成員按照它們被聲明的順序在內(nèi)存中順序存儲(chǔ),第一個(gè)成員的地址和整個(gè)結(jié)構(gòu)的地址相同。
自然對(duì)界(natural alignment)即默認(rèn)對(duì)齊方式,是指按結(jié)構(gòu)體的成員中size 最大的成員對(duì)齊。
struct Natural { char a; short b; char c; }
在上面的這個(gè)結(jié)構(gòu)體中,size最大的數(shù)據(jù)類型為short,長(zhǎng)度為兩個(gè)字節(jié)。因此,結(jié)構(gòu)體中所有成員變量都以2為單位對(duì)齊。
其大小為sizeof(Natural) = 6
指定對(duì)界
一般使用預(yù)處理指令#pragma pack來(lái)改變?nèi)笔〉膶?duì)界條件
-
使用偽指令#pragma pack (n),編譯器將按照n 個(gè)字節(jié)對(duì)齊
-
使用偽指令#pragma pack (),取消自定義字節(jié)對(duì)齊
-
如果#pragma pack (n)中指定的n 大于結(jié)構(gòu)體中最大成員的size,則其不起作用,結(jié)構(gòu)體仍然按照size 最大的成員進(jìn)行對(duì)界
#pragma pack (n) struct Natural { char a; int b; char c; }; #pragma pack ()
當(dāng)n 為4、8、16 時(shí),其對(duì)齊方式均一樣,sizeof(naturalalign)的結(jié)果都等于12。而當(dāng)n 為2時(shí),其發(fā)揮了作用,使得sizeof(Natural)的結(jié)果為6。
-
通過__attribute((aligned (n)))也可以讓所作用的結(jié)構(gòu)體成員對(duì)齊在n 字節(jié)邊界上,但它使用較少