Chris said:
How about (untested code):
typedef struct foo_s FooT;
struct foo_s
{
size_t size;
Foo *next;
ITYM `FooT' here.
};
char *fooAlloc(size_t size)
{
FooT *s = malloc(sizeof(FooT) + size);
`sizeof *s + size' would be slightly better, but
does the same thing.
if (!s)
{
do_error_handling();
}
s->size = size;
s->next = NULL; /* put it in a list or whatever */
return (char*) &s[1];
When I use this trick, I usually write `(char*)(s + 1)',
which means exactly the same thing but (I think) makes my
intention just a tiny bit clearer to the reader. IMHO.
}
void fooFree(char *p)
{
FooT *s = (FooT*)(p - sizeof(FooT));
/* do whatever to the structure */
free(s);
}
The standard says that malloc() returns an area aligned for any purpose,
so assigning it to a FooT* is valid. By the definition of array access,
s[1] points to a valid address in the allocated memory beyond the
initial structure. Similarly, converting back for the free() is valid
(assuming that you've been passed a valid pointer, but that's true of
any allocation system).
Sure -- but there's no array at all in this code,
and it isn't "the struct hack." You're achieving the
same memory layout the hack aims for, but you've lost
the syntactic convenience of being able to refer to
the extra space as if it were a struct element. I use
this technique fairly commonly when there's a string
of some sort associated with the struct, but to reclaim
the syntactic sugar I go ahead and "waste" a `char*'
struct element pointing to the string that immediately
follows the struct itself.
Note that trafficking in the "midpoint pointer" instead
of in the pointer to the `FooT' itself is an orthogonal
matter. It's legal, it works, but it gives up *all* chance
of accessing the other struct members conveniently. I don't
see much point to it.
The latest "C99" version of the Standard legitimizes the
struct hack, but introduces a new syntax: you declare `bar'
with no array size at all, as `char bar[]'. However, this is
still relatively new and not yet widely supported by available
compilers.
I don't think it's necessary (and is currently non-portable), since the
pointer to the 'extra' area can always be accessed by taking the address
of the next structure (or converting to char* and adding sizeof the
structure).
Yes, and if your tolerance for ugliness is high enough you
can even extend the technique to handle "extra" data of a type
with stricter alignment requirements than `char'. C99's "struct
un-hack" lets you achieve the same effect without all the grunge
*and* retains the syntactic convenience of letting you refer to
the "extra" data as part of the struct. I think that's worth
while; code that's easier to read is code that's less likely to
be written wrongly.