As the title states I was wondering how arrays of C-structs with a flexible array member behaves. Here is an example:
struct vector {
size_t length;
double array[];
};
The Wikipedia article says:
The
sizeof
operator on such a struct is required to give the offset of the flexible array member.
On my machine this corresponds to 8 bytes (sizeof(size_t)
). But what happens, when I do the following:
Obviously the array cannot hold the data of vector v0
, since it's only 3*8 bytes = 24 bytes wide. How can I deal with situations like this?
#define LENGTH 10
int main() {
struct vector arr[3];
struct vector *v0 = calloc(1, sizeof(*v0) + LENGTH * sizeof(v0->array[0]));
v0->length = LENGTH;
size_t i;
for (i = 0; i < v0->length; i++) {
v0->array[i] = (double) i;
}
struct vector v1;
struct vector v2;
arr[0] = *v0;
arr[1] = v1;
arr[2] = v2;
for (i = 0; i < arr[0].length; i++) {
printf("arr[0].array[%2zu] equals %2.0lf.\n", i, arr[0].array[i]);
printf(" v0->data[%2zu] equals %2.0lf.\n", i, v0->array[i]);
}
return 0;
}
For example, when I'm writing a library (header: mylib.h
, source: my lib.c
) and want to hide the implementation of one specific struct from the user (struct declared in header, defined in source - hidden). Sadly exactly this struct contains a flexible array member. Won't this lead to unexpected behavior, when the user tries to create an array of named structures?
Extra: Read more about the flexible array in the OpenSTD C Spec.
Just search for 'flexible array member'.
EDIT: The latest draft of the C11 Standard, the most up to date freely available reference for the C language is available here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
Structures with a flexible array as their last member cannot be used as members of other structures or as array elements. In such constructions, the flexible array cannot be used as it has a size of 0 elements. The C Standard quoted by Jonathan Leffler is explicit, although the language used is quite technical and the paragraphs cannot be found in the Standard by searching for flexible.
The compiler should have issued an error for your array of struct vector.
In your program, you should instead use an array of pointers to
struct vectors
, each pointing to an object allocated for the appropriate number of elements in the its flexible array.Here is a modified version:
You can't have arrays of structures with flexible array members.
The C standard, ISO/IEC 9899:2011, says:
Emphasis added — the italic part of that prohibits arrays of structures with flexible array members. You can have arrays of pointers to such structures, though, but each structure will be separately allocated.
This defines a flexible array member.
If you think about it, it makes sense. Pointer arithmetic and arrays rely on all the objects in the array being the same size (hence the equivalence of
a[i] == *(a + i)
, etc), so having an array of objects of varying size would break pointer arithmetic. An array of pointers isn't a problem because the pointers are all the same size, even if the objects pointed at are of different sizes.If you manage to get a compiler to ignore the violated constraint, then each element of the array will have a zero length flexible array member because the structures will be treated as having the size of the structure without the array member (that's the 'in most situations, the flexible array member is ignored' rule at work). But the compiler should reject an array of a structure type with a flexible array member; such code is violating a constraint (¶3 is in the constraints section; ¶18 is in the semantics section).