struct中的一个元素数组

Oxd*_*eef 9 arrays struct element

为什么某些struct使用单个元素数组,如下所示:

typedef struct Bitmapset
{
 int nwords;
 uint32 words[1];
} Bitmapset;
Run Code Online (Sandbox Code Playgroud)

为了方便后者的动态分配?

Chr*_*utz 16

总之,是的.

基本上,C99的方法是使用灵活的数组成员:

uint32 words[];
Run Code Online (Sandbox Code Playgroud)

一些前C99编译器让你逃脱:

uint32 words[0];
Run Code Online (Sandbox Code Playgroud)

但是保证它在所有编译器中工作的方法是:

uint32 words[1];
Run Code Online (Sandbox Code Playgroud)

然后,无论如何声明,您都可以使用以下方式分配对象:

Bitmapset *allocate(int n)
{
    Bitmapset *p = malloc(offsetof(Bitmapset, words) + n * sizeof(p->words[0]));
    p->nwords = n;
    return p;
}
Run Code Online (Sandbox Code Playgroud)

虽然为了获得最佳效果,您应该使用size_t而不是int.


Wil*_*son 6

这通常是为了允许对可变大小的结构实例进行惯用访问.考虑到您的示例,在运行时,您可能有一个在内存中布局的Bitmapset,如下所示:

-----------------
| nwords   |  3 |
| words[0] | 10 |
| words[1] | 20 |
| words[2] | 30 |
-----------------
Run Code Online (Sandbox Code Playgroud)

所以你最终得到一个运行时变量的uint32"悬挂"在结构的末尾,但是可以访问它们就好像它们在结构中内联定义一样.这基本上是(ab)使用C不进行运行时数组边界检查以允许您编写代码的事实:

for (int i = 0; i < myset.nwords; i++) {
  printf("%d\n", myset.words[i]);
}
Run Code Online (Sandbox Code Playgroud)

  • 不会以同样的方式工作.如果你这样做,那么单词[2]会说"跟随位于结构的'words'字段中的指针,然后进一步去2*8 == 16字节并访问那里的内存." 你必须(例如)malloc()一个单独的内存区域来包含堆中的单词数组,这可能会影响性能和易用性. (5认同)