链表

链表,在linux内核中非常常见。在分析 nand flash内核驱动时,在链表这里就卡住了,还是基础打得不牢啊!废话不多说,下面对链表进行一些简单的分析:

最基本的双向链表结构:struct list_head {

struct  list_head *next;

struct  list_head *prev;

} ;

链表的操作:添加和删除节点

void list_add   (struct list_head *new,struct list_head *head);//将new节点添加到head的头部

void list_add_tail (struct list_head *new,struct list_head *head);//将new节点添加到head的尾部


内核提供的链表节点类型只包含两个指针成员,不可能保存其他有用数据。一般的用法是将它嵌在需要组成链表的结构体类型中,如:

struct my_data {

struct list_head list;/*用于组成链表*/

int data;    /*有用数据*/

};

进行链表操作时,以其list成员作为代表,如:

struct my_data *new =kmalloc(sizeof(struct my_data),GFP_KERNEL);

list_add(&new->list,&my_list);

也就是说,每个结构体里有一个双向链表,我们是通过这双向链表把结构体连接起来的。所以说,从链表头出发,可以到达每一个链表节点,通过上一个链表,可以得到下一个链表节点的指针ptr,并不能得到链表节点所在的结构体。这就需要借助于一个函数:container_of(ptr,type,member)

ptr:    链表节点的指针

type:链表节点所在结构体的类型

member:链表节点

因此,可以用以下方法对链表中的数据进行遍历:

struct my_data {

struct list_head list;

int data;

}

struct list_head *pos

for(pos=my_list->next,pos!=&my_list,pos=pos->next)

{

struct my_data *data=list_entry(pos,struct my_data,list);

}

这样,data就指向了struct my_data结构体。


内核还提供了一系列的宏,来对链表进行遍历:

list_for_each(pos,head);//head为要遍历的链表,pos为(struct list_head *),每次循环,pos指向链表的下一个节点。用这个宏时,pos指向节点本,大多数情况下,需要指向包含它的结构体的指针,这就用到下面的宏。

list_for_each_entry(pos,head,member)此时,pos并不指向节点了,它指向包含节点的结构体。

下面是此宏的一个具体用法:

struct my_data *pos

list_for_each_entry(pos,&my_list,list){

pos->data=0;/*结构体的数据赋值为0*/

}


你可能感兴趣的:(struct,list,Flash,each,linux内核)