【发布时间】:2011-06-01 08:49:14
【问题描述】:
为什么有些struct使用单元素数组,如下:
typedef struct Bitmapset
{
int nwords;
uint32 words[1];
} Bitmapset;
为了方便后期动态分配?
【问题讨论】:
为什么有些struct使用单元素数组,如下:
typedef struct Bitmapset
{
int nwords;
uint32 words[1];
} Bitmapset;
为了方便后期动态分配?
【问题讨论】:
总之,是的。
基本上,C99 的做法是使用 flexible array member:
uint32 words[];
一些 C99 之前的编译器可以让您摆脱困境:
uint32 words[0];
但保证它适用于所有编译器的方法是:
uint32 words[1];
然后,无论它如何声明,您都可以使用以下方式分配对象:
Bitmapset *allocate(int n)
{
Bitmapset *p = malloc(offsetof(Bitmapset, words) + n * sizeof(p->words[0]));
p->nwords = n;
return p;
}
尽管为了获得最佳效果,您应该使用size_t 而不是int。
【讨论】:
Bitmapset *a[20] = { NULL }; 或Bitmapset **a = malloc(20 * sizeof *a);。
offsetof(Bitmapset, words[n]) 是一个扩展(恰好被大多数编译器支持)。为了严格遵守,请使用offsetof(Bitmapset, words) + n*sizeof(p->words[0])。
p->words[i] 优化为p->words[0],因为前者仅在为数组分配内存的情况下定义了行为元素,和的下标小于数组的大小(即为零)?我怀疑如果数组是间接访问结构中的最后一项,即使通常可能优化单项数组访问的编译器也会避免这样做,但是标准中是否有任何内容会禁止它(或证明代码假设编译器不会做)?
这通常是为了允许惯用地访问可变大小的结构实例。考虑到您的示例,在运行时,您可能有一个位图集,其布局在内存中,如下所示:
-----------------
| nwords | 3 |
| words[0] | 10 |
| words[1] | 20 |
| words[2] | 30 |
-----------------
因此,您最终会得到一个运行时可变数量的 uint32“挂”在结构的末尾,但可以像在结构中内联定义它们一样访问。这基本上是(ab)使用 C 不进行运行时数组边界检查的事实来允许您编写如下代码:
for (int i = 0; i < myset.nwords; i++) {
printf("%d\n", myset.words[i]);
}
【讨论】: