How does an array of structures with flexible array elements behave?

As the title says, I was wondering how C-structs arrays behave with an element of a flexible array element. Here is an example:

struct vector { size_t length; double array[]; }; 

The Wikipedia article says:

The sizeof operator in such a structure is required to give an offset to the flexible element of the array.

On my machine, this corresponds to 8 bytes ( sizeof(size_t) ). But what happens when I do the following:

Obviously, the array cannot store the data of the vector v0 , since it is only 3 * 8 bytes = 24 bytes wide. How can I deal with such situations?

 #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 write a library (header: mylib.h , source: my lib.c ) and want to hide the implementation of one specific structure from the user (the structure declared in the header defined in the source is hidden). Unfortunately, this structure contains the flexible element of the array. Could this lead to unexpected behavior when the user tries to create an array of named structures?

In addition . More on flexible array in OpenSTD C Spec .
Just find the "flexible array element".

EDIT : The latest draft of the C11 standard, the most current freely available link for the C language, is available here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

+5
source share
2 answers

Structures with a flexible array as the last member cannot be used as elements of other structures or array elements. In such constructions, a flexible matrix cannot be used, since it has a size of 0 elements. Standard C, cited by Jonathan Leffler, is explicit, although the language used is quite technical, and paragraphs cannot be found in the standard by searching for a flexible one.

The compiler should have thrown an error for your struct vector array.

Instead, you should use an array of pointers to struct vectors in your program, each of which points to an object allocated for the corresponding number of elements in its flexible array.

Here is a modified version:

 #include <stdio.h> #include <stdlib.h> struct vector { size_t length; double array[]; }; struct vector *make_vector(size_t n) { struct vector *v = malloc(sizeof(*v) + n * sizeof(v->array[0])); v->length = n; for (size_t i = 0; i < n; i++) { v->array[i] = (double)i; } return v; } int main(void) { struct vector *arr[3]; arr[0] = make_vector(10); arr[1] = make_vector(5); arr[2] = make_vector(20); for (size_t n = 0; n < 3; n++) { for (size_t i = 0; i < arr[n]->length; i++) { printf("arr[%zu]->array[%2zu] equals %2.0lf.\n", n, i, arr[0]->array[i]); } } return 0; } 
+2
source

You do not have arrays of structures with flexible array elements.

Standard C, ISO / IEC 9899: 2011, says:

6.7.2.1 Structure and Association Specifications

ΒΆ3 A structure or union should not contain an element with an incomplete or functional type (therefore, the structure should not contain an instance of itself, but may contain a pointer to the instance by itself), except that the last member of the structure with more than one named member may have an incomplete array type; such a structure (and any union containing, possibly recursively, an element that is such a structure) should not be a member of the structure or an array element.

Accent is added - the italic part of this prohibits arrays of structures with flexible array elements. However, you may have arrays of pointers to such structures, but each structure will be allocated separately.

ΒΆ18 As a special case, the last structure element with more than one named element may have an incomplete array type; this is called a flexible array element. In most situations, the flexible array element is ignored. In particular, the size of the structure looks as if the flexible element of the array were excluded, except that it may have a longer addition than an omission would mean. However, when the operator . (or -> ) has a left operand that has a (pointer to) structure with a flexible member of an array and names of right operands that are a member, it behaves as if this element were replaced by the longest array (with the same element type), which will not make the structure larger than the object being accessed; the offset of the array must remain equal to the element of the flexible array, even if it differs from the replacement matrix. If this array does not contain any elements, it will behave as if it had one element, but the behavior is undefined if attempts are made to access this element or create a pointer that passes by it.

This defines the flexible element of the array.

If you think about it, that makes sense. Arithmetic of pointers and arrays rely on all objects in the array having the same size (hence the equivalence of a[i] == *(a + i) , etc.), therefore, the presence of an array of objects of different sizes will break the pointer arithmetic. An array of pointers is not a problem because pointers are the same size, even if the specified objects have different sizes.

If you manage to force the compiler to ignore the violated constraint, then each element of the array will have a flexible array element with zero length, because the structures will be treated as having the size of the structure without a member of the array (which is the rule at work in most situations, the flexible array element is ignored). But the compiler must reject an array of structure type with a flexible array element; such a code violates the restriction (ΒΆ3 is in the restrictions section; ΒΆ18 is in the semantics section).

+3
source

Source: https://habr.com/ru/post/1245435/


All Articles