views:

94

answers:

4

Here is a snippet of the official Apple Documentation of AudioBufferList (Core Audio Data Types Reference):

AudioBufferList
Holds a variable length array of AudioBuffer structures.

struct AudioBufferList {
    UInt32      mNumberBuffers;
    AudioBuffer mBuffers[1];
};
typedef struct AudioBufferList  AudioBufferList;

Fields

mNumberBuffers
The number of AudioBuffer structures in the mBuffers array.

mBuffers
A variable length array of AudioBuffer structures.

If mBuffers is defined as AudioBuffer[1] it is not of variable length and thus mNumberBuffers is implicitly defined as 1.

Do I miss something here or is this just nonsense?

+2  A: 

This technique is something I've also seen in PostgreSQL, although there it's always marked with a comment

// VARIABLE SIZED STRUCTURE

or something like that. Basically the way it works is that the users of the structure are expected to understand that the size 1 of mBuffers is simply the initial size. To resize the structure, they realloc() the entire thing and just assume that any memory tacked on to the end "belongs" to the mBuffers list, even though the structure definition itself does not explain this.

Steven Schlansker
+3  A: 

Well that's because C before C99 requires a nonzero constant array size.

And mBuffers cannot be declared as AudioBuffer*, because the list is inplace.

And mBuffers cannot be declared as AudioBuffer, because the mBuffers[x] syntax is needed.

So AudioBuffer[1] is used.

If that structure is written just for C99 then the declaration would be

struct AudioBufferList {
    UInt32      mNumberBuffers;
    AudioBuffer mBuffers[];
};

(See also http://stackoverflow.com/questions/246977/flexible-array-members-in-c-bad.)

KennyTM
+2  A: 

From what I've been told, the mBuffers[1] bit is just an old C trick. Which allows for structure's member to be a variable length array. Know that it must be the last element in the struct, as you'll write past the size of the struct.

This must be allocated correctly. Or a bunch of puppies will die, etc..

Rev316
+2  A: 

It's what called the "struct hack" or (in C99) a "variable length array" (VLA). The basic idea is that the '1' is just a place-holder. When you use this structure, you allocate it dynamically, allocating enough space for the real data. For example, if you want 10 buffers, you'd allocate space something like:

AudioBufferList *a = malloc(sizeof (*a) + 9 * sizeof(AudioBuffer));
a->mNumberBuffers = 10;

Note that since it allocates space for one AudioBuffer as part of the struct itself, you subtract one from the number you really want to get the space to add on to the allocation.

Jerry Coffin