【问题标题】:One element array in struct结构中的一个元素数组
【发布时间】:2011-06-01 08:49:14
【问题描述】:

为什么有些struct使用单元素数组,如下:

typedef struct Bitmapset
{
 int nwords;
 uint32 words[1];
} Bitmapset;

为了方便后期动态分配?

【问题讨论】:

    标签: arrays struct element


    【解决方案1】:

    总之,是的。

    基本上,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

    【讨论】:

    • 谢谢。那么这个棘手的分配是否会对结构填充有问题,比如传递的 n 是否是奇数?
    • @Oxdeadbeef - 是的,我想。您不会真正将它们的数组存储在连续的内存中。如果你想要一个数组,最好使用Bitmapset *a[20] = { NULL };Bitmapset **a = malloc(20 * sizeof *a);
    • 语法offsetof(Bitmapset, words[n]) 是一个扩展(恰好被大多数编译器支持)。为了严格遵守,请使用offsetof(Bitmapset, words) + n*sizeof(p->words[0])
    • @Jed - 我不知道,虽然我应该猜到了。固定。
    • @ChrisLutz:标准中是否有任何内容禁止编译器将p->words[i] 优化为p->words[0],因为前者仅在为数组分配内存的情况下定义了行为元素,的下标小于数组的大小(即为零)?我怀疑如果数组是间接访问结构中的最后一项,即使通常可能优化单项数组访问的编译器也会避免这样做,但是标准中是否有任何内容会禁止它(或证明代码假设编译器不会做)?
    【解决方案2】:

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

    -----------------
    | 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]);
    }
    

    【讨论】:

    • 不会以同样的方式工作。如果你这样做了,那么 words[2] 会说“跟随位于结构的 'words' 字段中的指针,然后再走 2*8==16 个字节并访问那里的内存。”您必须(例如) malloc() 一个单独的内存区域来包含堆中的单词数组,这可能会影响性能和易用性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-04
    • 2018-12-16
    相关资源
    最近更新 更多