/* @author = s1n */
/*文中出现的源码均来自linux 3.16.41内核*/
1.实现双向循环链表的一般方法:
1 struct list_node1{ 2 struct list_node1 *next,*prev; 3 type1 m1; 4 type2 m2; 5 }; 6 struct list_node2{ 7 struct list_node2 *next,*prev; 8 type1 m1; 9 type2 m2; 10 };
如果对于每一种数据结构都定义了其特定的实现和对应的方法,对于具有大量不同数据结构,都要使用链表的系统中,无疑使代码变得重复和臃肿。因此需要实现一种通用的双向链表方法,对各种数据结构都能适用。
2.list_head的实现:
struct list_head { struct list_head *next, *prev; };
1).list_head头节点定义的两个宏,定义在/linux/list.h中
1 #define LIST_HEAD_INIT(name) { &(name), &(name) } //就是用head的地址初始化其两个成员next和prev ,使其都指向自己。 2 #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) 3 #define INIT_LIST_HEAD(ptr) do { \ 4 (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 5 } while (0)
则定义一个双向链表的头节点:
1 /*方法1*/ 2 struct list_head head; 3 LIST_HEAD_INIT(head); 4 5 /*方法2*/ 6 LIST_HEAD(head);
这样,我们就定义并初始化了一个头节点
3.list_head操作:
1 /** 2 * __list_add - Insert a new entry between two known consecutive entries. 3 * @new: 4 * @prev: 5 * @next: 6 * 7 * This is only for internal list manipulation where we know the prev/next 8 * entries 9 */ 10 static __inline__ void __list_add(struct list_head * new, 11 struct list_head * prev, struct list_head * next) 12 { 13 next->prev = new; 14 new->next = next; 15 new->prev = prev; 16 prev->next = new; 17 } 18 //这个函数在prev和next间插入一个节点new。 19 20 /** 21 * list_add - add a new entry 22 * @new: new entry to be added 23 * @head: list head to add it after 24 * 25 * Insert a new entry after the specified head. 26 * This is good for implementing stacks. 27 */
1 static __inline__ void list_add(struct list_head *new, struct list_head *head) 2 { 3 __list_add(new, head, head->next); 4 } 5 //这个函数在head节点后面插入new节点。 6 7 /** 8 * list_add_tail - add a new entry 9 * @new: new entry to be added 10 * @head: list head to add it before 11 * 12 * Insert a new entry before the specified head. 13 * This is useful for implementing queues. 14 */ 15 static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) 16 { 17 __list_add(new, head->prev, head); 18 }
2).删除节点操作:
1 /** 2 * __list_del - 3 * @prev: 4 * @next: 5 * 6 * Delete a list entry by making the prev/next entries point to each other. 7 * 8 * This is only for internal list manipulation where we know the prev/next 9 * entries 10 */ 11 static __inline__ void __list_del(struct list_head * prev, 12 struct list_head * next) 13 { 14 next->prev = prev; 15 prev->next = next; 16 } 17 18 /** 19 * list_del - deletes entry from list. 20 * @entry: the element to delete from the list. 21 * * Note: list_empty on entry does not return true after this, the entry is in 22 * an undefined state. 23 */ 24 static __inline__ void list_del(struct list_head *entry) 25 { 26 __list_del(entry->prev, entry->next); 27 } 28 29 /** 30 * list_del_init - deletes entry from list and reinitialize it. 31 * @entry: the element to delete from the list. 32 */ 33 static __inline__ void list_del_init(struct list_head *entry) 34 { 35 __list_del(entry->prev, entry->next); 36 INIT_LIST_HEAD(entry); 37 }
1 /** 2 * list_empty - tests whether a list is empty 3 * @head: the list to test. 4 */ 5 static __inline__ int list_empty(struct list_head *head) 6 { 7 return head->next == head; 8 }
4.一个结构体通过list_head实现双链表
1).如果某种结构体需要双向链表结构,则将list_head作为其中的成员:
1 struct kobject { 2 const char *name; 3 struct list_head entry; 4 struct kobject *parent; 5 struct kset *kset; 6 }
形成了如下的结构:
2).list_entry()
该函数是通过kobject 链表结构中的 list_head 成员entry访问下一个成员的宏:
,ptr : 是指向当前kobject结构对象中的数据成员entry,(char *)(ptr):entry成员地址,
,(char *)(ptr):entry成员地址----地址A;
,(unsigned long)(&((type *)0)->member)) : 将地址0转化为类型为type(struct kobject )对象,取member(entry)成员的地址----地址B
,(type *)(地址A-地址B): 得到kobject结构对象的首地址,转化为kobject对象
1 /** * list_entry - get the struct for this entry 2 * @ptr: the &struct list_head pointer. 3 * @type: the type of the struct this is embedded in. 4 * @member: the name of the list_struct within the struct. */ 5 6 #define list_entry(ptr, type, member) \ 7 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 8 9 //访问链表成员 10 kobject *obj = objList; 11 kobject *nextObj = (kobject *)list_entry(obj->entry->next,struct kobject,entry);
即为如下结构:
3).一个实例:
首先,定义如下结构体:
1 struct person 2 { 3 int age; 4 int weight; 5 struct list_head list; 6 };
现定义一指针:
struct list_head *pos = person;
则获取这个指针所指向的结构的变量:
struct person *one = list_entry(pos, struct person, list);
代入到宏中:
((struct person *)((char *)(pos)-(unsigned long)(&((struct person *)0)->list)))
1 /** 2 * list_for_each - iterate over a list 3 * @pos: the &struct list_head to use as a loop counter. 4 * @head: the head for your list. 5 */ 6 #define list_for_each(pos, head) \ 7 for (pos = (head)->next; pos != (head); pos = pos->next) 8 9 /** 10 * list_for_each_safe - iterate over a list safe against removal of list entry 11 * @pos: the &struct list_head to use as a loop counter. 12 * @n: another &struct list_head to use as temporary storage 13 * @head: the head for your list. 14 */ 15 #define list_for_each_safe(pos, n, head) \ 16 for (pos = (head)->next, n = pos->next; pos != (head); \ 17 pos = n, n = pos->next)
list_for_each()遍历整个head链表中的每个元素,每个元素都用pos指向。
而后者list_for_each_safe()使用了n作为一个临时的指针。若进行删除操作,当pos被删除后,还可以用n来获得下一个元素的位置。
6.总例:
1 #include <stdio.h> 2 #include "list.h" 3 4 struct person 5 { 6 int age; 7 8 int weight; 9 struct list_head list; 10 }; 11 12 int main(int argc, char* argv[]) 13 { 14 struct person *tmp; 15 struct list_head *pos, *n; 16 int age_i, weight_j; 17 18 // 定义并初始化一个链表头 19 struct person person_head; 20 INIT_LIST_HEAD(&person_head.list); 21 22 for(age_i = 10, weight_j = 35; age_i < 40; age_i += 5, weight_j += 5) 23 { 24 tmp =(struct person*)malloc(sizeof(struct person)); 25 tmp->age = age_i; 26 tmp->weight = weight_j; 27 28 // 把这个节点链接到链表后面 29 // 这里因为每次的节点都是加在person_head的后面,所以先加进来的节点就在链表里的最 30 后面 31 32 // 打印的时候看到的顺序就是先加进来的就在最后面打印 33 list_add(&(tmp->list), &(person_head.list)); 34 35 } 36 37 // 下面把这个链表中各个节点的值打印出来 38 printf("\n"); 39 printf("=========== print the list ===============\n"); 40 list_for_each(pos, &person_head.list) 41 { 42 // 这里我们用list_entry来取得pos所在的结构的指针 43 tmp = list_entry(pos, struct person, list); 44 printf("age:%d, weight: %d \n", tmp->age, tmp->weight); 45 } 46 printf("\n"); 47 48 // 下面删除一个节点中,age为20的节点 49 printf("========== print list after delete a node which age is 20 50 ==========\n"); 51 list_for_each_safe(pos, n, &person_head.list) 52 { 53 54 tmp = list_entry(pos, struct person, list); 55 if(tmp->age == 20) 56 { 57 list_del_init(pos); 58 free(tmp); 59 } 60 61 } 62 63 list_for_each(pos, &person_head.list) 64 { 65 tmp = list_entry(pos, struct person, list); 66 printf("age:%d, weight: %d \n", tmp->age, tmp->weight); 67 } 68 69 // 释放资源 70 list_for_each_safe(pos, n, &person_head.list) 71 { 72 tmp = list_entry(pos, struct person, list); 73 list_del_init(pos); 74 free(tmp); 75 } 76 77 return 0; 78 }