Can I "over-extend" an array by allocating more space to the enclosing struct? Can I "over-extend" an array by allocating more space to the enclosing struct? arrays arrays

Can I "over-extend" an array by allocating more space to the enclosing struct?


The standard C way (since C99) to do this would be using flexible array member. The last member of the structure needs to be incomplete array type and you can allocate required amount of memory at runtime.

Something like

struct __attribute__((__packed__)) weird_struct{    int some;    unsigned char value [ ];   //nothing, no 0, no 1, no nothing...}; 

and later

struct weird_struct *ws =    malloc(sizeof(struct weird_struct) + strlen("this to be copied") + 1);

or

struct weird_struct *ws =    malloc(sizeof(struct weird_struct) + sizeof("this to be copied"));

will do the job.

Related, quoting the C11 standard, chapter ยง6.7.2.1

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. 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. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.


Related to the one-element array usage, from online gcc manual page for zero-length array support option

struct line {  int length;  char contents[0];};struct line *thisline = (struct line *)  malloc (sizeof (struct line) + this_length);thisline->length = this_length;

In ISO C90, you would have to give contents a length of 1, which means either you waste space or complicate the argument to malloc.

which also answers the -1 part in the malloc() argument, as sizeof(char) is guaranteed to be 1 in C.


The Standard allows implementations to act in any way they see fit if code accesses an array object beyond its stated bounds, even if the code owns the storage that would be accessed thereby. So far as I can tell, this rule is intended to allow for a compiler given something like:

struct s1 { char arr[4]; char y; } *p;int x;...p->y = 1;p->arr[x] = 2;return p->y;

to treat it as equivalent to:

struct s1 { char arr[4]; char y; } *p;int x;...p->arr[x] = 2;p->y = 1;return 1;

avoiding an extra load step, without having to pessimistically allow for the possibility that x might equal 4. Quality compilers should be able to recognize certain constructs which involve accessing arrays beyond their stated bounds (e.g. those involving a pointer to a structure with a single-element array as its last element) and handle them sensibly, but nothing in the Standard would require that they do so, and some compiler writers take the attitude that permission for compilers to behave in nonsensical fashion should be interpreted as an invitation to do so. I think that behavior would be defined, even for the x==4 case (meaning the compiler would have to allow for the possibility of it modifying y), if the array write were handled via something like: (char*)(struct s1*)(p->arr)[x] = 2; but the Standard is not really clear on whether the cast to struct s1* is necessary.