Are flexible array members really necessary?

2019-01-24 07:04发布

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

2条回答
祖国的老花朵
2楼-- · 2019-01-24 07:35

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

查看更多
老娘就宠你
3楼-- · 2019-01-24 07:45

Those concepts are definitely not necessary as you have pointed out yourself.

The differences between the two that you have demonstrated are where your data is located in memory.

In the first example with flexible array your metadata and the array itself are in the same block of memory and can be moved as one block (pointer) if you have to.

In the second example your metadata is on the stack and your array is elsewhere on the heap. In order to move/copy it you will now need to move two blocks of memory and update the pointer in your metadata structure.

Generally flexible size arrays are used when you need to place an array and it's metadata spatially together in memory.

An example where this is definitely useful is for instance when placing an array with it's metadata in a file - you have only one continuous block of memory and each time you load it it will (most likely) be placed in a different location of your VM.

查看更多
登录 后发表回答