When I want to use a generalized set of linked list (or in my case, queue) code, I embed the linked list pointer inside the larger structure that I want to use it with. Then use the link field name when passing arguments to the linked list functions. And have a function that can convert from a linked list pointer to the larger struct pointer for when I get pointers back from my linked list. Something like the code you see below.
This idiom doesn't give you the type safety of C++, but the code is pretty clean, with the casting is localized into just a few functions.
// some representative bits of my linked list API
//
typedef void* PLINK;
extern PLINK LLAddToList(PLINK head, PLINK new);
extern PLINK LLNextItem(PLINK current);
// the structure I want to use it with
typedef struct _foo {
PLINK pLink;
int data1;
int data2;
} FOO;
// to allow for the link pointers to be some other than the first field
// we use this to go from link pointer to structure pointer.
FOO * FooFromPLink(PLINK current) {
return (FOO *)((char *)¤t - FIELD_OFFSET(FOO, pLink));
}
void MyFunction()
{
// this idiom to use the linklist code with a FOO struct
//
FOO * pfoo = // allocate and initialize a foo
LLAddToList(head, &pfoo->pLink);
// this idiom to traverse a list of FOOs, etc.
//
PLINK next = LLNextItem(head);
while (next)
{
pfoo = FooFromPLink(next);
// operate on foo.
next = LLNextItem(next);
}
}