I'd like to suggest a different approach. Instead of creating multiple list types for different kinds of data and using casting or macro gymnastics to apply the same algorithm to them, create a single generic list type that delegates type-specific behavior to different functions and attach those functions to the list type with function pointers. For example:
struct generic_node {
void *data;
struct generic_node *next;
};
struct generic_list {
struct generic_node head;
int (*cmp)(void * const a, void * const b);
void *(*cpy)(void * const);
void (*del)(void *);
};
cmp points to a function that will return -1 if *a < *b, 0 if *a == *b, and 1 if *a > *b, where a and b have been converted from void * to the proper pointer types. For example,
int compareInts(void * const a, void * const b)
{
int * const la = a;
int * const lb = b;
if (*a < *b) return -1;
if (*a == *b) return 0;
if (*a > *b) return 1;
}
int compareMyStruct(void * const a, void * const b)
{
struct myStruct * const la = a;
struct myStruct * const lb = b;
if (la->foo < lb->foo && strcmp(la->bar,lb->bar) < 0 && ...) return -1;
if (la->foo == lb->foo && strcmp(la->bar,lb->bar) == 0 && ...) return 0;
if (la->foo > lb->foo && strcmp(la->bar, lb->bar) > 0 && ...) return 1;
}
cpy points to a function that makes a deep copy of the input parameter:
void *copyInt(void * const data)
{
int *theCopy = malloc(sizeof *theCopy);
*theCopy = *((int *) data);
return theCopy;
}
void *copyMyStruct(void * const data)
{
struct myStruct * const lData = data;
struct myStruct *newStruct = malloc(sizeof *newStruct);
newStruct->foo = lData->foo;
newStruct->bar = malloc(strlen(lData->bar) + 1);
strcpy(newStruct->bar, lData->bar);
...
return newStruct;
}
And finally, del points to a function that deallocates the data items:
void delInt(void * data)
{
free(data);
}
void delMyStruct(void * data)
{
struct myStruct * lData = data;
free(lData->bar);
...
free(lData);
}
Now your list algorithms don't have to worry about type-specific behavior; they just invoke the appropriate function via the function pointer:
void listAdd(struct generic_list * const theList, void * const data)
{
struct generic_node *cur = &(theList->head);
struct generic_node *entry = malloc(sizeof *entry);
entry->data = theList->cpy(data);
while (cur->next != NULL && theList->cmp(cur->next->data, entry->data) < 0)
cur = cur->next;
entry->next = cur->next;
cur->next = entry;
}
/** */
void listClear(struct generic_list * const theList)
{
struct generic_node *cur = theList->head.next;
while (cur != NULL)
{
struct generic_node *entry = cur;
cur = cur->next;
theList->del(entry->data);
free(entry);
}
}