[轉]可變大小結構體如何定義詳解 - Perfect
一、背景
工作中,在通訊協議中常常看到TLV格式資料,不同的type id對應的字串長度大小不一樣。那麼該怎麼去定義一個結構體去管理這些資料呢?怎麼去定義一種可變大小的結構體?本文將講解如何定義可變大小結構體。
二、定義可變大小結構體
1、方法一:使用指標
1 typedef struct _S_HB_TIME_REPORT_INFO2 {3 uint16_t msg_id;4 uint16_t msg_buf_len;5 char *p_msg_buf;6 }__attribute__((packed)) S_HB_TIME_REPORT_INFO;
如上定義的結構體,成員變數p_msg_buf為一個指標,指向一個不確定長度的字串,長度由msg_buf_len決定。在使用時可以動態給p_msg_buf分配msg_buf_len的記憶體,也可以p_msg_buf指向一個已知地址的字串。
缺點:1)動態分配記憶體使用malloc,在使用之後容易忘記free,此時會產生記憶體洩漏。2)如果你使用S_HB_TIME_REPORT_INFO結構體的次數比較多,那麼就要malloc很多次,此時很容易產生記憶體碎片。我的建議是,能不使用malloc就儘量不要用malloc。我的通常做法是讓p_msg_buf指向一個已知地址的字串。3)不管是malloc分配記憶體還是靜態指向一個已知地址的字串,結構體裡面的成員變數char *p_msg_buf是與結構體分離的,不利於操作。
2、方法二:使用柔性陣列
2.1 什麼是柔性陣列?
柔性陣列既陣列大小待定的陣列, C語言中結構體的最後一個元素可以是大小未知的陣列,也就是所謂的0長度,所以我們可以用結構體來建立柔性陣列。
2.2 柔性陣列有什麼用途 ?
它的主要用途是為了滿足需要變長度的結構體,為了解決使用陣列時記憶體的冗餘和陣列的越界問題。
3.3 用法
在一個結構體的最後,申明一個長度為空的陣列,就可以使得這個結構體是可變長的。對於編譯器來說,此時長度為0的陣列並不佔用空間,因為陣列名本身不佔空間,它只是一個偏移量,陣列名這個符號本身代 表了一個不可修改的地址常量(注意:陣列名永遠都不會是指標!),但對於這個陣列的大小,我們可以進行動態分配,對於編譯器而言,陣列名僅僅是一個符號,它不會佔用任何空間,它在結構體中,只是代表了一個偏移量,代表一個不可修改的地址常量!對於柔性陣列的這個特點,很容易構造出變成結構體,如緩衝區,資料包等等。
1 typedef struct _S_HB_TIME_REPORT_INFO2 {3 uint16_t msg_id;4 uint16_t msg_buf_len;5 char msg_buf[0];6 }__attribute__((packed)) S_HB_TIME_REPORT_INFO;
我們可以用sizeof(S_HB_TIME_REPORT_INFO) 求得陣列大小為4,說明柔性陣列是不佔用記憶體的。這樣的變長陣列常用於網路通訊中構造不定長資料包,不會浪費空間浪費網路流量,比如我要傳送1024位元組的資料,如果用定長包,假設定長包的長度為2048,就會浪費1024個位元組的空間,也會造成不必要的流量浪費。
所以建議使用柔性陣列去定義可變大小結構體。
---------------------
作者:Perfect_Code
來源:CNBLOGS
原文:https://www.cnblogs.com/shiyk/p/9371019.html
版權宣告:本文為作者原創文章,轉載請附上博文連結!
內容解析By:CSDN,CNBLOG部落格文章一鍵轉載外掛