Linux内核通用链表

Linux 内核通用链表

    链表的结点不能包含万物,那么就让万物来包含结点

#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

//  遍历链表

#define list_for_each(n,head)\

    for(n=head->next;head!=n;n=n->next)

下面两句是重点!!!!!!!!!!!!!!!!

//计算结构成员member所在结构中的距离第一个成员地址编号的差值

#define offset(type,member) ((int)&(((type*)0)->member))

//计算返回实际的结构成员指针所在结构变量的首地址

#define node_to_obj(node,type,member)\

   ((type*)((void*)node-offset(type,member)))

//第二种遍历

#define list_for_each_entry(ojb,head,member)\

    for(obj = node_to_obj(head->next,typeof(*obj),member);\

    head!= &obj->member;\

    obj = node_to_obj(obj->member.next,typeof(*obj),member))

typedef struct Node

{

    struct Node* prev;

    struct Node* next;

}Node;

//  创建链表

Node* create_list(void)

{

    Node* head = malloc(sizeof(Node));

    head->next = head;

    head->prev = head;

    return head;

}

void _add_list(Node* p,Node* n,Node* node)

{

    p->next = node;

    n->prev = node;

    node->next = n;

    node->prev = p;

}

//  头添加

void add_head_list(Node* head,Node* node)

{

    _add_list(head,head->next,node);    

}

//尾添加

void add_tail_list(Node* head,Node* node)

{

    _add_lista(head->prev,head,node);

}

//删除结点

void _del_list(Node* node)

{

    node->next->prev = node->prev;

    node->prev->next = node->next;

    node->next = node;

    node->prev = node;

}

//判断链表是否为空

bool empty_list(Node* head)

{

    return head->next == head;

}

//头删除

Node* del_head_list(Node* head)

{

    if(empty_list(head)) return NULL;

    Node* temp = head->next;

    _del_list(temp);

    return temp;

}

//尾删除

Node* del_head_list(Node* head)

{

    if(empty_list(head)) return NULL;

    Node* temp = head->prev;

    _del_list(temp);

    return temp;

}

/*  下面是用户编写的代码 */

typedef struct Student

{

    Node node;

    char name[20];

    char sex;

    char age;

    float score;

    int id;

}Student;

int main(int argc,const char* argv[])

{

    Node* head = create_list();

    for(int i=0; i<10; i++)

    {

        Student* stu = malloc(sizeof(Student));

        sprintf(stu->name,"hehe%d",i);

        stu->sex = i%2?'w':'m';

        stu->age = i+18;

        stu->score = rand()%100;

        stu->id = 1000+i;

        add_head_list(head,&(stu->node));

    }

    Node* n = NULL;

    list_for_each(n,head)

    {

        Student* stu = (Student*)n;

        printf("%s %c %hhd %g %d\n",

        stu->name,stu->sex,stu->age,stu->score,stu->id);

    }

}

一、linux内核链表 1、普通链表的数据区域的局限性 之前定义数据区域时直接int data,我们认为我们的链表中需要存储的是一个int类型的数。但是实际上现实编程中链接中的节点不可能这么简单,而是多种多样的。 一般实际项目中的链表,节点中存储的数据其实是一个结构体,这个结构体中包含若干的成员,这些成员加起来构成了我们的节点数据区域。 2、一般性解决思路:即把数据区封装为一个结构体 (1)因为链表实际解决的问题是多种多样的,所以内部数据区域的结构体构成也是多种多样的。 这样也导致了不同程序当中的链表总体构成是多种多样的。 我们无法通过一套泛性的、普遍适用的操作函数来访问所有的链表,意味着我们设计一个链表就得写一套链表的操作函数(节点创建、插入、删除、遍历……)。 (2)实际上深层次分析会发现 不同的链表虽然这些方法不能通用需要单独写,但是实际上内部的思路和方法是相同的,只是函数的局部地区有不同。 实际上链表操作是相同的,而涉及到数据区域的操作就有不同 (3)问题 能不能有一种办法把所有链表中操作方法里共同的部分提取出来用一套标准方法实现,然后把不同的部分留着让具体链表的实现者自己去处理。 3、内核链表的设计思路 (1)内核链表中实现一个纯链表的封装,以及纯链表的各种操作函数 纯链表就是没有数据区域,只有前后向指针; 各种操作函数是节点创建、插入、删除、遍历。 这个纯链表本身自己没有任何用处,它的用法是给我们具体链表作为核心来调用。 4、list.h文件简介 (1)内核中核心纯链表的实现在include/linux/list.h文件中 (2)list.h中就是一个纯链表的完整封装,包含节点定义和各种链表操作方法。 二、内核链表的基本算法和使用简介 1、内核链表的节点创建、删除、遍历等 2、内核链表的使用实践 (1)问题:内核链表只有纯链表,没有数据区域,怎么使用? 使用方法是将内核链表作为将来整个数据结构的结构体的一个成员内嵌进去。类似于公司收购,实现被收购公司的功能。 这里面要借助container_of宏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaoyu1381

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值