Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are flexible array members really necessary?

A struct with a flexible array member, apparently, is not intended to be declared, but rather used in conjunction with a pointer to that struct. When declaring a flexible array member, there must be at least one other member, and the flexible array member must be the last member in that struct.

Let's say I have one that looks like this:

struct example{
    int n;
    int flm[]; 
}

Then to use it, I'll have to declare a pointer and use malloc to reserve memory for the structure's contents.

struct example *ptr = malloc(sizeof(struct example) + 5*sizeof(int)); 

That is, if I want my flm[] array to hold five integers. Then, I can just use my struct like this:

ptr->flm[0] = 1; 

My question is, shouldn't I be able to just use a pointer instead of this? Not only would it be compatible pre-C99, but I could use it with or without a pointer to that struct. Considering I already have to use malloc with the flm, shouldn't I just be able to do this?

Consider this new definition of the example struct;

struct example{
    int n; 
    int *notflm; 
}

struct example test = {4, malloc(sizeof(int) * 5)}; 

I'd even be able to use the replacement the same way as the flexible array member:

Would this also work? (Provided the above definition of example with notflm)

struct example test; 
test.n = 4; 
notflm = malloc(sizeof(int) * 5); 
like image 781
Theo Chronic Avatar asked Aug 01 '13 18:08

Theo Chronic


1 Answers

Pointers are not arrays. The basic reasons for choosing which to use are the same as they always are with arrays versus pointers. In the special case of flexible array members, here are some reasons you may prefer them over a pointer:

  • Reducing storage requirements. A pointer will enlarge your structure by (typically) 4 or 8 bytes, and you'll spend much more in overhead if you allocate the pointed-to storage separately rather than with a single call to malloc.

  • Improving access efficiency. A flexible array member is located at a constant offset from the structure base. A pointer requires a separate dereference. This affects both number of instructions required to access it, and register pressure.

  • Atomicity of allocation success/failure. If you allocate the structure and allocate storage for it to point to as two separate steps, your code for cleaning up in the failure cases will be much uglier, since you have the case where one succeeded and the other failed. This can be avoided with some pointer arithmetic to carve both out of the same malloc request, but it's easy to get the logic wrong and invoke UB due to alignment issues.

  • Avoiding need for deep-copy. If you use a flexible array instead of a pointer, you can simply memcpy (not assign, since assignment can't know the flexible array length) to copy the structure rather than having to copy the pointed-to data too and fix up the pointer in the new copy.

  • Avoiding need for deep-free. It's very convenient and clean to be able to just free a single object rather than having to free pointed-to data too. This can also be achieved with the "carving up a single malloc" approach mentioned above, of course, but flexible arrays make it easier and less error-prone.

  • Surely many more reasons...

like image 72
R.. GitHub STOP HELPING ICE Avatar answered Oct 02 '22 16:10

R.. GitHub STOP HELPING ICE