在一个C ++开源项目中,我看到了这一点。
struct SomeClass {
...
size_t data_length;
char data[1];
...
}
这样做有什么好处而不是使用指针?
struct SomeClass {
...
size_t data_length;
char* data;
...
}
我唯一能想到的是使用size 1数组版本,用户不会看到NULL。还有别的吗?
答案 0 :(得分:35)
有了这个,你不必在其他地方分配内存并使指针指向它。
诀窍是分配比sizeof (SomeClass)
更多的内存,并指向它SomeClass*
。然后,SomeClass
对象将使用初始内存,data
可以使用剩余的内存。也就是说,你可以说p->data[0]
但也可以说p->data[1]
等等,直到你达到你分配的内存的末尾。
可以指出,这种使用会导致未定义的行为,因为您声明您的数组只有一个元素,但访问它就好像它包含更多元素一样。但是真正的编译器确实允许这个具有预期意义,因为C ++没有替代语法来形成这些方法(C99有,它在那里被称为“灵活的数组成员”)。
答案 1 :(得分:19)
这通常是避免多个内存分配和解除分配的快速(和脏)方式,尽管它比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的空间。
答案 2 :(得分:10)
通常您将此视为结构的最终成员。然后malloc
结构的任何人,将在内存中连续分配所有数据字节作为一个块来“跟随”结构。
因此,如果您需要16个字节的数据,则需要分配如下的实例:
SomeClass * pObj = malloc(sizeof(SomeClass) + (16 - 1));
然后您可以像访问数组一样访问数据:
pObj->data[12] = 0xAB;
当然,您也可以通过一次通话释放所有内容。
data
成员按惯例是单项数组,因为较旧的C编译器(显然是当前的C ++标准)不允许零大小的数组。这里有很好的进一步讨论:http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
答案 3 :(得分:10)
在您的示例中,它们在语义上是不同的。
char data[1]
是一个有效的char数组,在堆栈上分配了一个未初始化的元素。你可以写data[0] = 'w'
,你的程序也是正确的。
char* data;
只是声明一个无效的指针,直到初始化为指向有效地址为止。
答案 4 :(得分:2)
可以将结构简单地分配为单个内存块,而不是必须释放的多个分配。
它实际上使用的内存较少,因为它不需要存储指针本身。
由于内存是连续的,缓存可能还有性能优势。
答案 5 :(得分:2)
这个特殊事物背后的想法是data
的其余部分直接在结构之后适合内存。当然,无论如何你都可以这样做。