我想提出一种不同的方法。与其为不同类型的数据创建多个列表类型并使用强制转换或宏体操对它们应用相同的算法,不如创建一个通用列表类型,将特定类型的行为委托给不同的函数,并将这些函数附加到具有函数的列表类型指针。例如:
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 指向一个函数,如果 *a < *b 则返回 -1,如果 *a == *b 则返回 0,如果 *a > *b 则返回 1,其中 a 和 b 已从 void * 转换为正确的指针类型. 例如,
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 指向一个对输入参数进行深拷贝的函数:
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;
}
最后,del 指向一个释放数据项的函数:
void delInt(void * data)
{
free(data);
}
void delMyStruct(void * data)
{
struct myStruct * lData = data;
free(lData->bar);
...
free(lData);
}
现在您的列表算法不必担心特定类型的行为;他们只是通过函数指针调用适当的函数:
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);
}
}