为什么使用数组大小​​1而不是指针?

在一个C ++开源项目中,我看到了这一点。

struct SomeClass { ... size_t data_length; char data[1]; ... } 

这样做有什么好处,而不是使用指针?

 struct SomeClass { ... size_t data_length; char* data; ... } 

我能想到的唯一的事情是大小为1的数组版本,用户不希望看到NULL。 还有别的事吗?

有了这个,你不必在其他地方分配内存,并使指针指向。

  • 没有额外的内存pipe理
  • 对内存的访问将更有可能撞到内存caching

诀窍是分配比sizeof (SomeClass)更多的内存,并使SomeClass*指向它。 然后,初始内存将被您的SomeClass对象使用,剩余的内存可以被data 。 也就是说,你可以说p->data[0]但也可以p->data[1]等等,直到你打到你分配的内存的末尾。

可以指出,这个用法会导致未定义的行为,因为你声明你的数组只有一个元素,但是访问它就好像它包含更多的元素一样。 但是真正的编译器确实允许这样做,因为C ++没有其他语法来expression这些方法(C99,在那里它被称为“灵活的数组成员”)。

这通常是一种避免多次内存分配和释放的快速(而且很脏)的方式,尽pipe它比C ++更具时尚性。

那就是,而不是这个:

 struct SomeClass *foo = malloc(sizeof *foo); foo->data = malloc(data_len); memcpy(foo->data,data,data_len); .... free(foo->data); free(foo); 

你做这样的事情:

 struct SomeClass *foo = malloc(sizeof *foo + data_len); memcpy(foo->data,data,data_len); ... free(foo); 

除了保存(de)分配调用之外,这还可以节省一些内存,因为没有指针空间,甚至可以使用空间,否则这些空间可能是struct padding。

在你的例子中它们在语义上是不同的。

char data[1]是一个有效的char数组,其中一个未初始化的元素在堆栈上分配。 你可以写data[0] = 'w' ,你的程序是正确的。

char* data; 只是声明一个无效的指针,直到初始化为指向一个有效的地址。

通常你把它看作是结构的最后一个成员。 然后谁结构,将所有的数据字节连续地分配在内存中作为一个块来“跟随”结构。

所以,如果你需要16字节的数据,你会分配一个像这样的实例:

 SomeClass * pObj = malloc(sizeof(SomeClass) + (16 - 1)); 

然后,您可以像访问数组一样访问数据:

 pObj->data[12] = 0xAB; 

当然,你也可以用一个电话解放所有的东西。

data成员是一个单项数组按照惯例,因为旧的C编译器(显然是当前的C ++标准)不允许零大小的数组。 好的进一步讨论在这里: http : //gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

  1. 该结构可以简单地分配为一个单独的内存块,而不是必须释放的多个分配。

  2. 它实际上使用较less的内存,因为它不需要存储指针本身。

  3. 由于内存是连续的,所以caching也可能具有性能优势。

这个特定的事情背后的想法是,其余的data直接在结构后适合内存。 当然,无论如何,你都可以这样做。