Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the order of members in a struct matter?

Tags:

c

struct

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?

like image 440
Milo Wielondek Avatar asked Nov 08 '14 14:11

Milo Wielondek


People also ask

How are structs organized in memory?

Struct members are stored in the order they are declared. (This is required by the C99 standard, as mentioned here earlier.) If necessary, padding is added before each struct member, to ensure correct alignment. Each primitive type T requires an alignment of sizeof(T) bytes.

Are struct members contiguous in memory?

They will not necessarily be contiguous in memory. This is due to struct padding. then they most likely will not be. However, in your particular case, you will still likely get padding after gender , to realign the struct to 8 bytes.

Can a struct have itself as a member?

A structure T cannot contain itself.

Do structs have members?

Can C++ struct have member functions? Yes, they can.


2 Answers

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.

like image 69
Sergey Kalinichenko Avatar answered Oct 01 '22 11:10

Sergey Kalinichenko


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).

like image 43
Brendan Avatar answered Oct 01 '22 12:10

Brendan