声明零大小的向量

4
以下内容是什么意思?
struct foo
{
...
char  bar[0];    // Zero size???
};

我问了我的同事,他们告诉我这与写void* bar是一样的。

据我所知,C指针只是一个4字节的变量(至少在32位机器上)。编译器如何知道bar [0]是一个指针(因此长度为4个字节)?这只是语法糖吗?

4个回答

5
你的同事说谎了。 (可能不是故意的,所以不要对他们生气或其他任何事情。)
这被称为柔性数组成员,在C99中写作char bar [];,而在C89中写作char bar [1];,有些编译器可以让你写成char bar [0];。 基本上,你只使用指向结构体的指针,并在末尾分配它们所有额外的空间:
const size_t i = sizeof("Hello, world!");
struct foo *p = malloc(offsetof(struct foo, bar) + i);
memcpy(p->bar, "Hello, world!", i);
// initialize other members of p
printf("%s\n", p->bar);

这样,p->bar 存储的字符串大小不受数组声明限制,但仍然在与其余struct相同的分配中完成(而不需要成员为char *并需要两个malloc和两个free来设置它)。


啊,现在我明白了。这样结构实例就包含在连续的内存区域中。如果 "bar" 是一个指针,那么它会指向另一个内存块。因此,灵活数组允许用单个 memcopy 复制结构,例如。我发现这种结构在Linux内核中存在,实际上,从内核空间到用户空间的复制只使用了一个memcopy。 - Emiliano
1
除了单个的“memcpy”(这是一个很大的优点),它还只需要单个的“malloc”(如果它是一种你需要制造许多对象的类型,那么这可能会相对昂贵)。@happy_emi - Chris Lutz
当然可以。 (顺便说一下,我是指copy_to_user,而不是memcpy。只是为了记录。) - Emiliano

3

克里斯的回答是正确的,但我可能会稍微不同地分配对象。

int n = ...; // number of elements you want
struct foo *p = malloc(offsetof(struct foo, bar[n]));

然后使用迭代器遍历它

for (int i = 0; i < n; ++i) {
  p->bar[i] = ...;
}

重点是Chris的答案有效,因为sizeof(char)==1,但对于另一种类型,您必须明确乘以sizeof *bar

我忘记在哪里看到过 offsetof(struct foo, bar[n]) 技巧,但感谢提醒。这比我的版本好多了。 - Chris Lutz
@Chris,也许是雷蒙德的博客 - Alex Budovski

0
这应该是一个编译时错误!只有动态分配的数组可以分配为0大小。

一些(懒惰的?)编译器在 C99 标准化 char bar[]; 语法之前,允许人们声明可变数组成员为 char bar[0];。所以这可能不是一个错误。 - Chris Lutz

0

数组也可以通过指针访问(索引是隐式指针)。 所以我怀疑,如果他们告诉你这样做,这将被解释为一个指针。由于它是一个零长度的数组,它可能会指向下一个值(我希望在那个结构体中有一些东西跟随?)。

这只是怀疑,不是知识。 :)

虽然这不是你想要做的事情... 如果他们想要一个指针,他们应该使用一个指针。如果他们不能告诉你为什么它存在,那么它就不应该存在。


我想给一个标签命名。但是该字段在结构的底部声明。 - Emiliano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接