GNU/GCC
在标准 C/C++
基础上做了有实用性的扩展, 零长度数组(Arrays of Length Zero
) 就是其中一个知名的扩展。在一个结构体的最后, 申明一个长度为0的数组, 就可以使得这个结构体是可变长的。这种结构体要求:第一,0长度数组放在最后,第二,成员不能只有0长度数组,至少还应该有其他成员。比起在结构体中声明一个指针变量、再进行动态分 配的办法,这种方法效率要高。因为在访问数组内容时,不需要间接访问,避免了两次访存。
sizeof这个结构体类型时,0长度数组不算字节;开辟空间(malloc)时,根据实际需求开辟数组空间。
优点:比起在结构体中声明一个指针变量、再进行动态分 配的办法,这种方法效率要高。因为在访问数组内容时,不需要间接访问,避免了两次访存。
struct Packet
{
int state;
int len;
char cData[0]; //这里的0长结构体就为变长结构体提供了非常好的支持
};
举例:设想一个场景, 我们在网络通信过程中使用的数据缓冲区, 缓冲区包括一个len字段和data字段, 分别标识数据的长度和传输的数据, 我们常见的有几种设计思路:第一,定长数据缓冲区, 设置一个足够大小 MAX_LENGTH
的数据缓冲区;第二,设置一个指向实际数据的指针, 每次使用时, 按照数据的长度动态的开辟数据缓冲区的空间;第三,使用可变数组。
第一:
// 定长缓冲区
struct max_buffer
{
int len;
char data[MAX_LENGTH];
};
/// 开辟
if ((mbuffer = (struct max_buffer *)malloc(sizeof(struct max_buffer))) != NULL)
{
mbuffer->len = CURR_LENGTH;
memcpy(mbuffer->data, "Hello World", CURR_LENGTH);
printf("%d, %s\n", mbuffer->len, mbuffer->data);
}
/// 销毁
free(mbuffer);
mbuffer = NULL;
第二:
//指针
struct point_buffer
{
int len;
char *data;
};
// 开辟
if ((pbuffer = (struct point_buffer *)malloc(sizeof(struct point_buffer))) != NULL){
pbuffer->len = CURR_LENGTH;
if ((pbuffer->data = (char *)malloc(sizeof(char) * CURR_LENGTH)) != NULL)
{
memcpy(pbuffer->data, "Hello World", CURR_LENGTH);
printf("%d, %s\n", pbuffer->len, pbuffer->data);
}
}
// 销毁
free(pbuffer->data);
free(pbuffer);
pbuffer = NULL;
第三:
// 0长度数组
struct zero_buffer
{
int len;
char data[0];
};
// 开辟
if ((zbuffer = (struct zero_buffer *)malloc(sizeof(struct zero_buffer) + sizeof(char) * CURR_LENGTH)) != NULL)
{
zbuffer->len = CURR_LENGTH;
memcpy(zbuffer->data, "Hello World", CURR_LENGTH);
printf("%d, %s\n", zbuffer->len, zbuffer->data);
}
// 销毁
free(zbuffer);
zbuffer = NULL;