您的位置:首页 > 运维架构 > Linux

linux 驱动学习之list链表机制

2017-10-27 17:24 417 查看
转载:http://blog.chinaunix.net/uid-27122224-id-3277511.html

双向链表

struct list_head{
struct list_head *next, *prev;
};
struct dlist{
int no;
void* data;
struct dlist *prev, *next;
};


结构:



struct list_head结构的操作

1.初始化

就是用head的地址初始化其两个成员next和prev ,使其都指向自己。

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)


具体使用:

struct list_head head;

LIST_HEAD_INIT(head);

LIST_HEAD(head);

2.增加节点的函数

相关api:
static inline void __list_add();
static inline void list_add();
static inline void list_add_tail();

具体实现:
/**
* __list_add - Insert a new entry between two known consecutive entries.
* @new:
* @prev:
* @next:
*
* This is only for internal list manipulation where we know the prev/next
* entries
*/
static __inline__ void __list_add(struct list_head * new,
struct list_head * prev, struct list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
//这个函数在prev和next间插入一个节点new。

/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
//这个函数在head节点后面插入new节点。

/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}


3.删除节点的函数

1.list_del(struct list_head *entry)是从链表中删除entry节点。
2.list_del_init(struct list_head *entry) 不但从链表中删除节点,还把这个节点的向前向后指针都指
向自己,即初始化。

具体实现:
/**
* __list_del -
* @prev:
* @next:
*
* Delete a list entry by making the prev/next entries point to each other.
*
* This is only for internal list manipulation where we know the prev/next
* entries
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* * Note: list_empty on entry does not return true after this, the entry is in
* an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}

/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}


3.判断链表是否为空

/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}


4.通过list_head变量来获取整个结构的变量

/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))


举例来说:

struct person *one = list_entry(pos, struct person, list);

把list_entry 展开

((struct person )((char )(pos) - (unsigned long)(&((struct person *)0)->list)))

其中

1.(unsigned long)(&((struct person *)0)->list)的意思就是取list 变量在struct person结构中的偏移量。

2.((char
4000
)(pos) - (unsigned long)(&((struct person )0)->list))

就是将pos指针往前移动offset位置,即是本来pos是struct list_head类型,它即是list。即是把

pos指针往struct person结构的头地址位置移动过去,如上图的pos和虚箭头。

当pos移到struct person结构头后就转 成(struct person *)指针,这样就可以得到struct person

*变量了。



5.循环遍历双向链表

/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)

/**
* list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)


list_for_each(pos, head)是遍历整个head链表中的每个元素,每个元素都用pos指向。

list_for_each_safe(pos, n, head)是用于删除链表head中的元素,不是上面有删除链表元素的函数了

吗,为什么这里又要定义一个这样的宏呢。看下这个宏后面有个safe字,就是说用这个宏来删除是安全的,

直接用前面的那些删除函数是不安全的。

原因:

list_for_each

删除pos后,list_for_each要移到下一个元素,还需要用pos来取得下一个元素,但pos的指向已 经改变,如果不直接退出而是在继续操作的话,就会出错了。

ist_for_each_safe

这里我们使用了n作为一个临时的指针,当pos被删除后,还可以用n来获得下一个元素的位置。

6.实现举例

#include <stdio.h>
#include "list.h"

struct person
{
int age;

int weight;
struct list_head list;
};

int main(int argc, char* argv[])
{
struct person *tmp;
struct list_head *pos, *n;
int age_i, weight_j;

// 定义并初始化一个链表头
struct person person_head;
INIT_LIST_HEAD(&person_head.list);

for(age_i = 10, weight_j = 35; age_i < 40; age_i += 5, weight_j += 5)
{
tmp =(struct person*)malloc(sizeof(struct person));
tmp->age = age_i;
tmp->weight = weight_j;

// 把这个节点链接到链表后面
// 这里因为每次的节点都是加在person_head的后面,所以先加进来的节点就在链表里的最
后面

// 打印的时候看到的顺序就是先加进来的就在最后面打印
list_add(&(tmp->list), &(person_head.list));

}

// 下面把这个链表中各个节点的值打印出来
printf("\n");
printf("=========== print the list ===============\n");
list_for_each(pos, &person_head.list)
{
// 这里我们用list_entry来取得pos所在的结构的指针
tmp = list_entry(pos, struct person, list);
printf("age:%d, weight: %d \n", tmp->age, tmp->weight);
}
printf("\n");

// 下面删除一个节点中,age为20的节点
printf("========== print list after delete a node which age is 20
==========\n");
list_for_each_safe(pos, n, &person_head.list)
{

tmp = list_entry(pos, struct person, list);
if(tmp->age == 20)
{
list_del_init(pos);
free(tmp);
}

}

list_for_each(pos, &person_head.list)
{
tmp = list_entry(pos, struct person, list);
printf("age:%d, weight: %d \n", tmp->age, tmp->weight);
}

// 释放资源
list_for_each_safe(pos, n, &person_head.list)
{
tmp = list_entry(pos, struct person, list);
list_del_init(pos);
free(tmp);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 链表 struct
相关文章推荐