12

Why some struct uses a single element array, such as follows:

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

To make it convenient for latter dynamic allocation?

Oxdeadbeef
  • 1,033
  • 2
  • 11
  • 26

2 Answers2

18

In a word, yes.

Basically, the C99 way to do it is with an flexible array member:

uint32 words[];

Some pre-C99 compilers let you get away with:

uint32 words[0];

But the way to guarantee it to work across all compilers is:

uint32 words[1];

And then, no matter how it's declared, you can allocate the object with:

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

Though for best results you should use size_t instead of int.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • Thanks. So will this tricky allocation has a problem for the struct padding thing, say if the passed n is an odd number? – Oxdeadbeef Dec 30 '10 at 03:28
  • @Oxdeadbeef - Yes, I suppose. You won't really store an array of them in contiguous memory. If you wanted an array of them you'd probably be better off using `Bitmapset *a[20] = { NULL };` or `Bitmapset **a = malloc(20 * sizeof *a);`. – Chris Lutz Dec 30 '10 at 06:23
  • 1
    The syntax `offsetof(Bitmapset, words[n])` is an extension (which happens to be supported by most compilers). For strict compliance, use `offsetof(Bitmapset, words) + n*sizeof(p->words[0])`. – Jed Mar 24 '12 at 16:29
  • @Jed - I didn't know that, though I should have guessed. Fixed. – Chris Lutz Mar 24 '12 at 16:57
  • @ChrisLutz: Is there anything in the standard that would forbid a compiler from optimizing `p->words[i]` as `p->words[0]`, since the former only has defined behavior in the case where the allocated memory exists for the array element, *and* the subscript is less than the size of the array (i.e. is zero)? I suspect even compilers which might normally optimize single-item array accesses will refrain from doing so if the array is the last item in an indirectly-accessed structure, but is there anything in the standard which would forbid it (or justify code's assumption that compilers won't do it)? – supercat Mar 26 '12 at 20:51
  • @supercat - I don't think so, but I'd have to consult the standard, and I don't have a copy of C11 yet. Also I have work to get done, so I'll get back to you on that. – Chris Lutz Mar 26 '12 at 21:12
  • @ChrisLutz: Was there ever anything in any earlier version of the standard that would forbid a compiler from making such an optimization? – supercat Mar 26 '12 at 21:40
7

This is usually to allow idiomatic access to variable-sized struct instances. Considering your example, at runtime, you may have a Bitmapset that is laid out in memory like this:

-----------------
| nwords   |  3 |
| words[0] | 10 |
| words[1] | 20 |
| words[2] | 30 |
-----------------

So you end up with a runtime-variable number of uint32 "hanging off" the end of your struct, but accessible as if they're defined inline in the struct. This is basically (ab)using the fact that C does no runtime array-bounds checking to allow you to write code like:

for (int i = 0; i < myset.nwords; i++) {
  printf("%d\n", myset.words[i]);
}
Will Robinson
  • 2,169
  • 1
  • 13
  • 8