Spiro Trikaliotis said:
Well, a separate memory allocation is not needed. You can alloc
sizeof(struct) + extra bytes, and then have bar point to "after the
struct".
Or is there anything else in the standard that forbids this?
Yes, that's another possible approach. There are some drawbacks. If
you make a copy of the structure, the pointer still points back to the
original structure (for example if you want to expand the array with
realloc()). If the array is of something other than a character type,
there's no good way to align it properly.
Overall, I'd say the classic "struct hack" is a better approach. It's
effectively portable to most or all pre-C99 implementations, and it's
portable to any conforming C99 implementation with a slightly
different syntax. You could probably use it portably with a
preprocessor test for __STDC_VERSION__.
Here's a sample program, that I *think* is portable to all conforming
C99 implementations and to any C90 implementation that supports the
classic struct hack (though in the latter case it may allocate
slightly more memory than it needs to).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
#define FLEXIBLE /* empty definition */
#else
#define FLEXIBLE 1
#endif
struct hack {
int len;
char str[FLEXIBLE];
};
#define MESSAGE "hello, world"
int main(void)
{
struct hack *ptr = malloc(sizeof *ptr + sizeof MESSAGE);
ptr->len = strlen(MESSAGE);
strcpy(ptr->str, MESSAGE);
printf("ptr->len = %d\n", ptr->len);
printf("ptr->str = \"%s\"\n", ptr->str);
return 0;
}
As for why C90 didn't choose to bless existing practice, I suspect
that the committee wanted to allow for range-checking implementations.
The struct hack in its classic form depends on being able to access an
array beyond its declared bounds, which invokes undefined behavior but
happens to work. C99 avoided this by introducing a new syntax in
which the array doesn't have declared bounds, so a range-checking
implementation can still do its checking in the normal case.