結構體中最後乙個元素是長度為0的陣列

2021-09-01 16:27:03 字數 1368 閱讀 1000

在linux源**中,有很多的結構體最後都定義了乙個元素個數為0個的陣列,如/usr/include/linux/if_pppox.h中有這樣乙個結構體: 

struct pppoe_tag __attribute ((packed));

又如在asterisk的原始碼中的pbx.c: 

struct  ast_ignorepat  ;   

結構體最後的長度為0的陣列是gcc中廣泛使用技巧,常用來構成可變長緩衝區。 

在建立時,malloc一段結構體大小加上可變長資料長度的空間給它:malloc(sizeof(struct  pppoe_tag)+  buff_len),可變長部分按陣列訪問方式訪問;釋放時,直接把整個結構體free掉就可以了。

例子如下: 

struct pppoe_tag *sample_tag; 

__u16 sample_tag_len = 10; 

sample_tag = (struct pppoe_tag *)malloc( sizeof(struct pppoe_tag) + sizeof(char) * sample_tag_len); 

sample_tag->tag_type = 0xffff; 

sample_tag->tag_len = sample_tag_len; 

sample_tag->tag_data[0]=…. …

釋放時: 

free(sample_tag)

這樣的好處有兩個:  

一次分配解決問題,省了不少麻煩。為了防止記憶體洩漏,如果是分兩次分配(結構體和緩衝區),那麼要是第二次malloc失敗了,必須回滾釋放第乙個分配的結構體。這樣帶來了編碼麻煩。

其次,分配了第二個緩衝區以後,如果結構裡面用的是指標,還要為這個指標賦值。同樣,在free這個buffer的時候,用指標也要兩次free。而且小記憶體的管理是非常困難的,如果用指標,這個buffer的struct部分就是小記憶體了,在系統內存在多了勢必嚴重影響記憶體管理的效能。要是用空陣列把struct和實際資料緩衝區一次分配大塊問題,就沒有這個問題。

所以,結構體最後使用0或1的長度陣列的原因,主要是為了方便的管理記憶體緩衝區,如果你直接使用指標而不使用陣列,那麼,你在分配記憶體緩衝區時,就必須分配結構體一次,然後再分配結構體內的指標一次,(而此時分配的記憶體已經與結構體的記憶體不連續了,所以要分別管理即申請和釋放)而如果使用陣列,那麼只需要一次就可以全部分配出來;反過來,釋放時也是一樣,使用陣列,一次釋放,使用指標,得先釋放結構體內的指標,再釋放結構體。還不能顛倒次序。

這個技巧其實就是分配一段連續的的記憶體,減少記憶體的碎片化。在linux作業系統開發或者嵌入式開發,這種技巧尤其常見。

ps:某些編譯器不支援長度為0的陣列的定義,在這種情況下只要將它定義成char tag_data[1],使用方法相同。

結構體中最後乙個成員陣列定義0個元素的意義

struct mydata 在結構中,data是乙個陣列名 但該陣列沒有元素 該陣列的真實位址緊隨結構體mydata之後,而這個位址就是結構體後面資料的位址 如果給這個結構體分配的內容大於這個結構體實際大小,後面多餘的部分就是這個data的內容 這種宣告方法可以巧妙的實現c語言裡的陣列擴充套件。實際...

結構體中最後乙個成員陣列定義0個元素的意義

struct mydata 在結構中,data是乙個陣列名 但該陣列沒有元素 該陣列的真實位址緊隨結構體mydata之後,而這個位址就是結構體後面資料的位址 如果給這個結構體分配的內容大於這個結構體實際大小,後面多餘的部分就是這個data的內容 這種宣告方法可以巧妙的實現c語言裡的陣列擴充套件。實際...

在結構體最後定義乙個長度為0的字元陣列(技巧)

定義乙個結構體如下 typedef struct buffer s buffer t 大家注意到最後那個長度為0的字元陣列了吧?不知道你疑惑了沒。嘿嘿!這個常用技巧常用來構成緩衝區 陣列名就代表了該結構體後面資料的起始位址 而且無需初始化,不佔空間 而如果用指標的話,我們還要初始化,而且還要佔空間 ...