零长度数组
1 零长度数组概念
GCC/GNU在标准的C/C++基础上做了又实用性的拓展,零长度数组就是其中一个知名的拓展。多数情况下,其应用在变长数组中,其定义如下:
typedef struct
{
uint32_t length;
uint8_t payload[0];//这里的0长结构体就为变长结构体提供了非常好的支持。
} packet;
首先对0长度数组,也叫柔性数组,做一个解释:
- 用途:长度为0的数组的主要用途就是为了满足需要变长度的结构体
- 用法:在一个结构体的最后,申明一个长度为0的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量,数组名这个符号本身代表一个不可修改的地址常量。
2 0长度数组的用途
在网络通信过程中使用的数据缓冲区,缓冲区包括一个len字段和data字段,分别标识数据的长度和传输的数据,我们常见的有几种设计思路:
- 定长数据缓冲区,设置一个足够大小的数据缓冲区。但是多数情况下,缓冲区的大部分空间都是浪费掉的。
- 设置一个指向实际数据的指针,每次使用时,按照数据的长度动态的开辟数据缓冲区的空间。需要额外开辟数据域的空间,释放的时候也需要显式释放数据域的空间。
所以最好使用零长数组。
3 实例
#pragma pack(1)
typedef struct
{
uint32_t age; // 4
gender gen; // 4
char name[32]; // 32
} person;
#pragma pack(1)
typedef struct
{
uint32_t length;
uint8_t payload[0];
} packet;
我们想将person结构体作为payload。
person *p = new person{18, models::female, "zhuangjuan"};
packet *pkt = (packet *)malloc(sizeof(packet) + sizeof(person));
pkt->length = sizeof(*p);
memcpy(pkt->payload, p, sizeof(*p));
auto pp = (person *)pkt->payload;
std::cout << "pp->age:" << (uint32_t)pp->age << endl;
std::cout << "pp->gen:" << pp->gen << endl;
std::cout << "pp->name:" << pp->name << endl;
delete pkt;
delete p;