[转]可变大小结构体如何定义详解 - 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博客文章一键转载插件