在linux内核中实现通用链表的思想:
1.定义两个结构体,一个结构体(这里我称其为内层结构体)是只有指针成员,用于负责结构体的连接,前驱与后继等,另一个结构体(这里叫做外层机构体)相当于是留给用户自己定义的 ,自己想要什么存放什么类型的数据类型就自己定义什么样的类型,在一个就是将上一个结构体当作成员在这个结构体中,用的时候就只需要使用接口选择插入删除方法即可,而不用考虑怎样插入或者删除等具体的细节,仅仅是在做插入删除等操作的时候自己开辟空间,然后自己释放掉,这样就实现了通用链表的功能。
代码中有几点需要注意的或者需要说明的地方:
1)
link_for_each_safe(pos,phead,t)
/*释放空间,销毁函数
,这里是定义了一个宏#define link_for_each(pos, phead) for (pos = phead->next; pos != NULL; pos = pos->next),就是一个for循环,定义宏主要就是为了封装
*/
{
TEST*tmp = link_entry(pos, TEST, node);
/*link_entry(pos,TEST,node)这也是一个宏定义,功能就是找到外层结构体,也就是用户自己定义的结构体的入口地址*/
link_del(phead);
//free(pos);//pos不是用malloc申请的空间,用free释放程序就会崩溃,而这个空间用free(tmp)也就释放了
free(tmp);
}
2)关于找外层结构体入口地址定义的宏:
*efine link_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))*))
/*
(&((type *)0)->member)将虚拟的0地址强转化为外层结构体类型,于是就有内层结构体的成员,再将内层结构体的地址取出来,而此地址减去0地址就是相对外层结构体的偏移地址,就算出来了每个内层结构体在外层结构体中的偏移地址,(unsigned long)再将其强转化为没有任何意义的数字,
((type *)((char *)(ptr)这个将传进来的ptr内层结构体的地址先强转化为char类型,减去偏移地址就是外层结构体的地址,但此时是char*类型 ,再强转化为外层结构体类型,就找到了外层结构体的入口地址,就可以对其数据域读取,释放整个空间了。这种方法就可以通过一个头指针而读取所有数据域部分,而不需要用户定义好多指针指向每一个结构体
*/
2.个人改进:
个人觉得用户自己用的时候还要自己申请空间 ,自己释放,感觉很繁琐,能不能我们给用户留一个接口,用户只需要调用一个函数就可以完成空间的释放,和插入和删除呢?于是我用了回掉函数 :
bool link_del_tail(NODE_EX*phead, void(*pfunc)(NODE_EX*));
//尾删
bool link_del_head(NODE_EX*phead, void(*pfunc)(NODE_EX*));//头删
bool destory_link_ex(NODE_EX*phead, void(*pfunc)(NODE_EX*));//释放所有用户开辟的空间
/*
void my_free(NODE_EX*p)
{
TEST*tmp=link_entry(p,TEST,node);
free(tmp);
}用户只需要自己定义一个这样的释放函数,用户就可以调用一次这个接口函数实现所有节点的空间释放*/
bool show_ex(NODE_EX*phead, void(*pfunc)(NODE_EX*));
/*
void my_print_ex(NODE_EX*p)
{
TEST*tmp = link_entry(p, TEST, node);
printf("%d ",tmp->data);
}用户只需要自己写一个这样的打印函数,我们调用接口函数调用这个打印函数实现所有节点的数据打印,不需要繁琐的循环 */
//显示打印链表中的每个元素
其他的插入删除等操作接口函数也可以用类似的方法实现,但是用户自己定义的回掉函数也就增多了,当然有些回掉的函数可以合并 ,但是自我感觉主函数里面的确简介了很多,主函数要实现的功能一目了然。
例:
封装的代码:
bool destory_link_ex(NODE_EX*phead, void(*pfunc)(NODE_EX*))
{
if (phead == NULL)
{
return false;
}
NODE_EX*p = phead->next;
while (p != NULL)
{
p = p->next;
link_del_head(phead,pfunc);
}
free(phead);
retur true;
}
用户自己写的回掉函数:
void my_free(NODE_EX*p)
{
TEST*tmp=link_entry(p,TEST,node);
free(tmp);
}
欢迎评论指正!