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