开发者

Flexible array member in C-structure

Quoting from the C-std section 6.7.2.1,

struct s { int n; double d[]; };

This is a valid structure declaration. I am looking for some practical use of this kind of syntax. To be precise, how is t开发者_Go百科his construct any more or less powerful than keeping a double* as the 2nd element? Or is this another case of 'you-can-do-it-in-multiple-ways'?

Arpan


The C FAQ answers precisely this question. The quick answer is that this structure will include the double array inside the structure rather than a pointer to an array outside the structure. As a quick example, you could use your structure as in this example:

struct s mystruct = malloc(sizeof(struct s) + 5 * sizeof(double));
s.n = 12;
s.d[0] = 4.0;
s.d[1] = 5.0;
s.d[2] = 6.0;
s.d[3] = 7.0;
s.d[4] = 8.0;

And so on - the size of the array you care about is included in the allocation, and then you can use it just like any array. Normally such a type contains the size as part of the structure, since using the + trick to skip through an array of type s will be necessarily complicated by this situation.

To your added question 'how is this construct any more or less powerful than keeping a [pointer] as the 2nd element?', it's no more powerful per se, but you don't need to keep a pointer around, so you would save at least that much space - also when you are copying the structure, you would also copy the array, rather than a pointer to an array - a subtle difference sometimes, but very important other times. 'You-can-do-it-in-multiple-ways' is probably a good explanation, but there are cases where you would specifically want one design or the other.


The primary advantage is that a flexible array member allows you to allocate a single block of memory for the array along with the other data in the struct (with a pointer, you'd typically end up with two separately allocated blocks).

It's also useful with data transmitted by quite a few network protocols, where the incoming stream is defined the same way -- an integer defining a length, followed by that many units (typically bytes/octets) of data. You can (typically) use a type-pun to overlay a struct with a flexible array member onto a buffer filled with such data, and work with it directly instead of having to parse it out into pieces and then work with the pieces individually.


You can use it to add header fields to dynamically allocated arrays, the most common one of which would be its size:

struct int_array
{
    size_t size;
    int values[];
};

struct int_array *foo = malloc(sizeof *foo + 42 * sizeof *foo->values);
foo->size = 42;

...

for(size_t i = 0; i < foo->size; ++i)
    foo->values[i] = i * i;

You could achieve similar results by using an int * member instead and allocating the array seperately, but it would be less efficient both in terms of memory (additional pointer, heap management for 2nd memory block) and runtime (additional indirection, 2nd allocation).


I've seen this used on Windows for strings which are tagged by their length. The character data is stored directly after the length in memory, keeping everything together neatly.

typedef struct {
    SIZE_T bytes;
    TCHAR chars[];
} tagged_string;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜