If you're only going to port to machines (compilers) that support C99, then you could consider using the 'flexible array members', which is the portable version of the 'struct hack'.
§6.7.2.1 Structure and union specifiers
¶16 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. With two
exceptions, the flexible array member is ignored. First, the size of the structure shall be
equal to the offset of the last element of an otherwise identical structure that replaces the
flexible array member with an array of unspecified length.106) Second, 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.
¶17 EXAMPLE Assuming that all array members are aligned the same, after the declarations:
struct s { int n; double d[]; };
struct ss { int n; double d[1]; };
the three expressions:
sizeof (struct s)
offsetof(struct s, d)
offsetof(struct ss, d)
have the same value. The structure struct s
has a flexible array member d
.
106) The length is unspecified to allow for the fact that implementations may give array members different
alignments according to their lengths.
In context, that means you might write:
typedef struct mystruct
{
int x;
struct y *list[];
} mystruct; // Note that this is necessary; C++ automatically recognizes mystruct; C does not.
To allocate space, you might use:
mystruct *h1 = (mystruct *)malloc(sizeof(mystruct) + 10 * sizeof(struct y *));
This allocates a mystruct
with enough space for 10 pointers in the array. You can later resize the memory with:
mystruct *new_h1 = (mystruct *)realloc(h1, sizeof(mystruct) + 20 * sizeof(struct y *));
if (new_h1 == 0)
...handle out of memory error, but note that h1 is still valid...
h1 = new_h1; // Safe
(Note that I carefully do not assign to h1
on the reallocation; to do so would leak memory if you get a memory allocation failure.)
You can reference them as if the array was there:
h1->list[0] = ...;
Note that you cannot have an array of mystruct
, but you can have an array of pointers to mystruct
. It is also up you to keep tabs on the size of the array; you'd normally do something like have one of the fixed members record the size allocated.