Does the order of members in a struct matter?

I have found a peculiar behaviour in C. Consider the below code:

 struct s {
     int a;
 };      

 struct z {
     int a;
     struct s b[];
 };  

 int main(void) {
     return 0;
 }   

It compiles just fine. Then change the order of the members of struct z like so

struct z {
    struct s b[];
    int a; 
};  

And all of a sudden we get the compilation error field has incomplete type 'struct s []'.

Why is that?


The order of fields in a struct does matter - the compiler is not allowed to reorder fields, so the size of the struct may change as the result of adding some padding.

In this case, however, you are defining a so-called flexible member, an array the size of which you can change. The rules for flexible members are that

  • There may never be more than one such member,
  • If present, the flexible member must be the last one in the struct, and
  • The struct must have at least one member in addition to the flexible one.

Take a look at this Q&A for a small illustration on using flexible structure members.


The compiler can't calculate how much memory struct s b[]; will consume. This means that if the structure has any fields after it, the compiler can't figure out the where those fields are.

It used to be (in old versions of C) that (e.g.) struct s b[]; wasn't allowed as a member of a structure. This made efficient memory management annoying. For a simple example, imagine you've got a structure containing a "name" string (that could be just a few characters or a lot of them). You could use a fixed size array that's big enough for the largest name (which wastes space), or use a pointer and allocate 2 pieces of memory (one for the structure and one for the variable length name string). Alternatively, you could use a pointer and make it point to extra space past the end of the structure, which ends up something like this:

    length = strlen(my_string);
    foo = malloc(sizeof(MYSTRUCTURE) + length + 1);
    foo->name = (void *)foo + sizeof(MYSTRUCTURE);   // Set pointer to extra bytes past end of structure
    memcpy(foo->name, my_string, length + 1);

This was the most efficient option; but it's also ugly and error prone.

To work around that, compilers added non-standard extensions to allow "unknown size arrays" at the end of the structure. This made it a little easier for programmers and made it a little more efficient (as there's no need for the additional pointer member). This ended up being adopted by the C standard (maybe in C99 - I don't remember).


The order of member usually matters (i.e. some padding might be inserted between fields) but in your specific case you're using a flexible member array, this is standardized in C99 - 6.7.2.1.16

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

Your struct s b[]; member is meant to be used to access dynamic heap allocations for multiple struct s elements.