Linux驱动学习——内核链表

传统链表的特点:

1.传统链表的指针域跟节点的数据类型一样

2.传统链表的指针域指向下一个节点的首地址

3.传统链表中拿第一个节点作为头结点


linux内核链表的特点:

对于指针域内核进行抽象,定义一个数据结构struct list_head作为节点的指针域

1.节点的指针域不再和节点的数据类型保持一致,大家都是struct list_head

2.节点的指针域不再指向下一个节点的首地址,而是指向下一个节点的指针域,需要配合container_of来获取这个节点的首地址,通过首地址再去访问数据域的信息

3.一般来说内核用structlist_head作为链表头,即链表头没有数据域。

好处:如果有多种链表,如果使用struct list_head作为指针域,那么这些链表的操作都是跟list_head相关,所以可以定义一套操作函数。原因:内核链表的指针域跟节点的数据类型无关!

4.关于内核链表structlist_head的所有操作方法    include/linux/list.h

 

内核链表使用

1. 首先定义节点的数据结构

2. 然后将structlist_head嵌入其中

     struct fox {

       intdata;

       chardata1;

       structlist_head list; //指针域

     };

3.定义一个链表头 //不包含数据域

    struct list_head head;

    INIT_LIST_HEAD(&head); //初始化链表头

4. 分配节点

     struct fox *fox1 = kzalloc(sizeof(struct fox),

                            GFP_KERNEL); 

     struct fox *fox2 = kzalloc(sizeof(struct fox),

                            GFP_KERNEL); 

      struct fox *fox3 = kzalloc(sizeof(struct fox),

                            GFP_KERNEL); 

4. 调用list_add/list_add_tail添加节点

     list_add(&head, &fox1->list);

    list_add(&head, &fox2->list);

    list_add(&head, &fox3->list);

    顺序:3->2->1

     list_add_tail(&head, &fox1->list);

    list_add_tail(&head, &fox2->list);

    list_add_tail(&head, &fox3->list);

    顺序:1->2->3

5. 调用list_del删除节点

     list_del(&fox1->list);

6. 遍历链表list_for_each/list_for_each_safe

     struct list_head *pos; //存放每一个节点指针域的首地址

     list_for_each (pos, &head) {

       //获取节点信息

     }

 

     struct list_head *pos; //存放下一个节点指针域的首地址

     struct list_head *n; //存放下下一个节点指针域的首地址

     list_for_each_safe(pos, n, &head) {

            //获取节点信息

    }

   区别在于:如果仅仅是遍历链表,它们都一样,没什么区别。

   如果在遍历链表的时候,进行了删除节点的操作,必须使用后者,否则造成断链,内存非法访问!

 

6. 遍历链表时,每次都是取出的是节点的指针域,如果要访问这个节点的数据域,还是使用list_entry来获取节点的首地址。

 #define list_entry(ptr, type, member) \

       container_of(ptr,type, member)

ptr:已知成员的首地址

type:结构体名

member:已知成员的变量名

返回值:结构体的首地址

 

container_of:

#define container_of (ptr, type, member)     ({                        \
	const typeof (  ((type *)0)->member )  *_mptr = (ptr);    \
	(type *)(  (char *)_mptr - offsetof(type,member)  );})


#define offsetof (type, member)  (size_t)(&(  ((type *)0)->member ))



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值