跳转至

0长数组

https://blog.csdn.net/zhizhengguan/article/details/111472884

零长度数组概念

众所周知, GNU/GCC 在标准的 C/C++ 基础上做了有实用性的扩展, 零长度数组(Arrays of Length Zero) 就是其中一个知名的扩展.

多数情况下, 其应用在变长数组中, 其定义如下

C++
struct Packet
{
    int state;
    int len;
    char cData[0]; //这里的0长结构体就为变长结构体提供了非常好的支持
};

首先对 0长度数组, 也叫柔性数组 做一个解释 :

  • 用途 : 长度为0的数组的主要用途是为了满足需要变长度的结构体

  • 用法:在一个结构体的最后,申明一个长度位0的数组,就可以使得这个结构体是可变长的。

对于编译器来说,此时长度位0的数组不占空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代表了一个不可修改的地址常量

(注意 : 数组名永远都不会是指针!), 但对于这个数组的大小, 我们可以进行动态分配。

注意 :如果结构体是通过calloc、malloc或 者new等动态分配方式生成,在不需要时要释放相应的空间。

  • 优点:比起在结构体中声明一个指针变量、再进行动态分 配的办法,这种方法效率要高。因为在访问数组内容时,不需要间接访问,避免了两次访存。
  • 在结构体中,数组为0的数组必须在最后声明,使 用上有一定限制。

零长度数组的用途

我们设想这样一个场景, 我们在网络通信过程中使用的数据缓冲区, 缓冲区包括一个len字段和data字段, 分别标识数据的长度和传输的数据, 我们常见的有几种设计思路

  • 定长数据缓冲区, 设置一个足够大小 MAX_LENGTH 的数据缓冲区
  • 设置一个指向实际数据的指针, 每次使用时, 按照数据的长度动态的开辟数据缓冲区的空间.

我们从实际场景中应用的设计来考虑他们的优劣. 主要考虑的有, 缓冲区空间的开辟, 释放和访问.

C++
#include <iostream>
#include <string.h>

using namespace std;

struct Arr0 {
  int len;
  char *data;
};

struct Arr1 {
  uint64_t len;
  char data[1];
};

int main() {
  cout << "Arr0 size: " << sizeof(Arr0) << endl;
  cout << "Arr1 size: " << sizeof(Arr1) << endl;

  struct Arr1 *arr1ptr = (struct Arr1*)malloc(sizeof(struct Arr1) + 10);
  cout << "arr1ptr size: " << sizeof(*arr1ptr) << endl;

  arr1ptr->len = 10;
  memcpy(arr1ptr->data, "1234567890", 10);
  cout << "data: " << arr1ptr->data << endl;

  return 0;
}


Result:

Arr0 size: 16
Arr1 size: 16
arr1ptr size: 16
data: 1234567890
C++
#include <iostream>
#include <string.h>

using namespace std;

struct Arr0 {
  int len;
  char *data;
};

struct Arr1 {
  uint64_t len;
  char data[0];
};

int main() {
  cout << "Arr0 size: " << sizeof(Arr0) << endl;
  cout << "Arr1 size: " << sizeof(Arr1) << endl;

  struct Arr1 *arr1ptr = (struct Arr1*)malloc(sizeof(struct Arr1) + 10);
  cout << "arr1ptr size: " << sizeof(*arr1ptr) << endl;

  arr1ptr->len = 10;
  memcpy(arr1ptr->data, "123456789", 10);
  cout << "data: " << arr1ptr->data << endl;

  return 0;
}

Result
Arr0 size: 16
Arr1 size: 8
arr1ptr size: 8
data: 123456789

如果使用以下的方式,则data需要单独申请内存,且与struct Arr1不连续。

C++
struct Arr1 {
  uint64_t len;
  char *data;
};