Reputation: 1861
Defererencing a pointer
to a struct
with a Flexible Array Member (FAM) doesn't "copy" the FAM?
That seems to be the behavior, according to this program, which creates as instance of a struct with an FAM and then inspects the "binary layout" of both a pointer to the struct and a dereference of the struct.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
typedef struct{
uint8_t idim;
uint32_t data[];
}array_t; // https://gustedt.wordpress.com/2011/03/14/flexible-array-member/
int64_t x_bdim = sizeof(array_t) + sizeof(uint32_t)*0x2;
array_t* _x = aligned_alloc(0x1000,x_bdim);
array_t x = *_x;
uint8_t* raw;
x.idim = 0xff;
x.data[0x0] = 0x11111111;
x.data[0x1] = 0x22222222;
_x->idim = 0xff;
_x->data[0x0] = 0x11111111;
_x->data[0x1] = 0x22222222;
printf("%'ld %'ld %'ld\n", sizeof(array_t), sizeof(array_t) + sizeof(uint32_t)*0x2, x_bdim);
putchar(0x0a);
raw = (uint8_t*)_x;
for(int i=0; i<x_bdim; ++i)
printf("%02x\n", raw[i]);
putchar(0x0a);
for(int i=0; i<0x2; ++i)
printf("%08x\n", _x->data[i]);
putchar(0x0a);
raw = (uint8_t*)&x;
for(int i=0; i<x_bdim; ++i)
printf("%02x\n", raw[i]);
putchar(0x0a);
for(int i=0; i<0x2; ++i)
printf("%08x\n", x.data[i]);
}
Am I missing something, or is this correct? Is the morale of the story that we shouldn't deference (pointers to) structs with a Flexible Array Member, because we only get the "header" of the struct and not the full array data?
Upvotes: 2
Views: 145
Reputation: 222660
C 2018 6.7.2.1 18 says:
… In most situations, the flexible array member is ignored…
and nothing in the C standard says the flexible array member is used (is part of the value) when the structure is used, as in array_t x = *_x;
. So the fact that the array member is not copied in this initialization is due to nothing in the standard saying it is copied.
The standard says two more notable things about flexible array members. The next sentence allows for padding to serve the alignment requirement of the flexible array member:
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.
And the sentence after that says that accessing that member (as with x->data
) behaves as if there were indeed an array there, as large as the memory provided for it allows.
Thus this last sentence allows you to manually access data in flexible array members, but the first sentence does not require the compiler to do anything with them automatically.
The reason for this is of course that the compiler cannot in general know the size of the flexible array member. The other answers (so far) state this incorrectly; they say the compiler does not know the size. In the code shown, the compiler can of course see the size, so its lack of knowledge is not the reason the flexible array member is not copied. More accurately, the reason is the compiler cannot know the size in all situations where the structure is used, since the memory reservation may be out of sight of the code currently being compiled, so the general rule is that the flexible array member is not treated as part of the basic structure, even when the memory reservation is visible.
Upvotes: 2
Reputation: 43278
That would be correct. The compiler does not know the size of the array and assumes 0 for such operations, including copy, return, assign, and compare. In effect, the flexible array is after the struct.
GCC's prototype syntax was more obvious. They had it written as uint32_t data[0];
Upvotes: 2
Reputation: 62563
A bit of technicality - dereferencing the pointer is a misnomer here. The actual question is about copying structs with the FAM.
Your observation is correct, if you try to copy a struct with FMA, FMA portion will not be copied. The reason is quite simple - since compiler doesn't know the size of the size of allocated storage, it can not copy the FMA "tail".
Upvotes: 2