linux内核实现的通用链表思想

本文介绍了一种在Linux内核中实现通用链表的方法,并提供了一些实用的宏定义及回掉函数来简化用户操作,包括节点的插入、删除以及遍历等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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);
}
                                                                                                               欢迎评论指正!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值