赞
踩
C 语言本身并不自带集合(Collection)工具,当我们需要把结构体(struct)实例串联起来时,就需要在结构体内声明指向下一实例的指针,构成所谓的“链表”。而为了实现对链表的操作,我们需要另外实现一系列的函数,例如添加、删除、搜索、复制等等。而利用 Kernel 源代码中自带的 list.h,则可以方便地实现任意类型结构体的串联。
假设我有一个表示学生资料的结构体:
- #define MAX_STRING_LENGTH 50
-
- typedef struct student {
- char first_name[MAX_STRING_LENGTH];
- char last_name[MAX_STRING_LENGTH];
- unsigned int age;
- } student_t;
传统的做法,当我们需要将一系列学生的数据串联起来,那我们需要在该结构体内部添加一枚指针:
- typedef struct student {
- char first_name[MAX_STRING_LENGTH];
- char last_name[MAX_STRING_LENGTH];
- unsigned int age;
- struct student *next; /* Look at dis ;p */
- } student_t;
几乎每位 C 语言学习者都有在教科书中见过此类实现方法。但是这样做的缺点是:我们需要额外编写一系列函数,实现对该类型链表的操作。然而,稍微复杂点的项目内,有个十几个结构体那是很平常的事情。如果我们想为它们都实现链表功能,那我们就需要为每个类型的结构体编写一套函数,然后我们就累 shi 了。
有没有一种更为通用的办法呢?不需要顾及结构体本身的类型,就可以简简单单地把它们串起来。有点类似 Java 中的 LinkedList,如果我需要把一堆 Student 类的对象管理起来,那就很简单:
LinkedList<Student> lstStudents = new LinkedList<Student>();
完事儿!接着直接把对象往 lstStudents 里面放就可以了。
Linux 内核的源代码中有一个工具头文件 list.h,里面定义了一系列的宏(macro),帮助我们实现对任意类型结构体的串联。然而原始版本的 list.h 是供内核使用的,并不能直接被使用在用户空间(user space)的程序内。好在有网友对其进行了改写,使得其可以被使用在一般应用程序内。因为博客系统的限制,我无法将源代码一并贴上,大家可以自行下载:list.h 。较之 Github 上最新版的 list.h,该修改版提供的宏不是很全面,你可以根据自己的需要,从 Github 摘取、添加新宏。
为了利用 list.h 实现链表功能,首先我们需要对我们的结构体做一点小小的改动:
- #include "list.h"
-
- typedef struct student {
- char first_name[MAX_STRING_LENGTH];
- char last_name[MAX_STRING_LENGTH];
- unsigned int age;
- struct list_head node_student;
- } student_t;
首先毫无悬念的,我们需要将 list.h 包含到我们的程序,接着在结构体内,我们添加一个类型为 struct list_head
的字段node_student
。这个字段就像是链条上的环扣,一环一环地将所有实例串联起来。接下去我们需要一个函数,来创建该结构体的实例:
- student_t *make_student(const char *fn, const char *ln, unsigned int a) {
- student_t *stu = NULL;
-
- if ((stu = calloc(1, sizeof(struct student))) == NULL) {
- return NULL; /* Failed to allocate memory. */
- }
- if (strlen(fn) > (MAX_STRING_LENGTH - 1)) {
- return NULL; /* First name too long. */
- }
- if (strlen(ln) > (MAX_STRING_LENGTH - 1)) {
- return NULL; /* Last name too long. */
- }
-
- strcpy(stu->first_name, fn);
- strcpy(stu->last_name, ln);
- stu->age = a;
- return stu;
- }
函数代码比较简单,就不费口舌解释了。
现在在我们的 main 函数内,我们将创建一系列 student_t 结构体的实例,并把它们串联起来:
- struct list_head class;
- INIT_LIST_HEAD(&class);
-
- student_t *stu = NULL;
-
- /* Create students. */
- if ((stu = make_student("Pierre", "Dupont", 16)) == NULL) {
- fprintf(stderr, "Failed to create Pierre.\n");
- return -1;
- }
- list_add_tail(&stu->node_student, &class);
-
- if ((stu = make_student("Hugot", "Badeaux", 18)) == NULL) {
- fprintf(stderr, "Failed to create Hugot.\n");
- return -1;
- }
- list_add_tail(&stu->node_student, &class);
-
- if ((stu = make_student("Celine", "Brousseau", 17)) == NULL) {
- fprintf(stderr, "Failed to create Celine.\n");
- return -1;
- }
- list_add_tail(&stu->node_student, &class);
这里我们首先创建一个链表 class,并用宏 INIT_LIST_HEAD 对其进行初始化。紧接着我们创建三名学生,分别叫:Pierre.Dupont,Hugot.Badeaux 和 Celine.Brousseau。每创建一名学生,我们就用宏 list_add_tail,将其添加到链表 class 内。list_add_tail 取两个参数,首先是结构体内用于串联实例的“环扣”node_student 的指针,其次是链表本身的指针,即 class。
完成对链表的初始化之后,我们试着打印出链表内所有的学生信息:
- /* Print all students in class. */
- printf("All the students in class.\n");
- list_for_each_entry(stu, &class, node_student) {
- printf("First name: %s\n", stu->first_name);
- printf("Last name: %s\n", stu->last_name);
- printf("Age: %u\n\n", stu->age);
- }
对链表的遍历是通过宏 list_for_each_entry
来实现的,它取三个参数,分别是:一个结构体类型的指针,链表的指针,以及结构内“环扣”的名称,即 node_student
。程序编译时,该宏会被替换成一个 for 循环,遍历链表内所有的元素,并且打印在终端上。
现在学校组织一次春游,为此我们利用宏 LIST_HEAD
添加了另一个新的链表 bus。使用 LIST_HEAD
来创建空链表相对简单,不需要先声明,再用 INIT_LIST_HEAD
进行初始化。现在,我们需要把班级上所有的学生都移到公车 bus 内:
- LIST_HEAD(bus);
-
- /* Moving all students into bus. */
- printf("Moving all the students into the bus.\n");
- list_splice_init(&class, &bus);
- if (list_empty(&class)) {
- printf("No more student in class.\n");
- }
- printf("\n");
-
- /* Print all student in bus. */
- list_for_each_entry(stu, &bus, node_student) {
- printf("%s %s (%u) is in the bus.\n", stu->first_name, stu->last_name, stu->age);
- }
- printf("\n");
宏 list_splice_init
取两个参数,分别为原链表指针和新链表指针。使用该宏之后,class 链表内的所有元素就会被导出到 bus 链表内。接着我们再用宏 list_empty
测试链表 class 是否为空。顺利完成对学生的移动之后,我们再一次使用 list_for_each_entry
,逐一打印出新链表 bus 内的所有学生。不出意外的话,我们会发现 class 链表已为空,且所有学生都被成功转移到了新链表 bus 内。
新的麻烦来了,在校车即将出发之际,妹子 Celine 突然决定不去了,要回家。那我们只能将 Celine 从校车中移出,然后再重新清点学生人数。
- student_t *tmp = NULL;
-
- /* Celine wanna go home. */
- printf("Celine wants to go home, remove her.\n");
- list_for_each_entry_safe(stu, tmp, &bus, node_student) {
- if (strcmp(stu->first_name, "Celine") == 0) {
- list_del(&stu->node_student);
- free(stu);
- }
- }
- printf("\n");
-
- /* Print remaining students in bus. */
- printf("Remaining students in bus.\n");
- list_for_each_entry(stu, &bus, node_student) {
- printf("%s %s (%u) is in the bus.\n", stu->first_name, stu->last_name, stu->age);
- }
- printf("\n");
我们首先用宏 list_for_each_entry_safe
遍历链表 bus 内的所有学生,当我们找到 Celine 的时候,则调用宏 list_del
将其从链表内删除。list_del
只取一个参数,即目标元素内“环扣”的指针。此外 list_for_each_entry
和 list_for_each_entry_safe
的唯一区别在于,list_for_each_entry_safe
可以在遍历的过程当中删除链表内的元素,且不会造成错误。较之 list_for_each_entry
,list_for_each_entry_safe
需多取一个参数 tmp,其同样为结构体类型的指针,用于在遍历过程,临时保存链表元素。在删除 Celine 之后,我们发现 Pierre 和 Hugot 还老老实实地坐在校车内。
程序的最后,校车成功抵达目的地,我们将所有剩余的学生(Pierre 和 Hugot)从校车内移出,并释放系统资源:
- /* End of demo. */
- printf("End of demo, free all resources.\n");
- list_for_each_entry_safe(stu, tmp, &bus, node_student) {
- printf("Removing student: %s %s\n", stu->first_name, stu->last_name);
- list_del(&stu->node_student);
- free(stu);
- }
-
- return 0;
编译完成之后,试着运行程序,终端输出为:
- All the students in class.
- First name: Pierre
- Last name: Dupont
- Age: 16
-
- First name: Hugot
- Last name: Badeaux
- Age: 18
-
- First name: Celine
- Last name: Brousseau
- Age: 17
-
- Moving all the students into the bus.
- No more student in class.
-
- Pierre Dupont (16) is in the bus.
- Hugot Badeaux (18) is in the bus.
- Celine Brousseau (17) is in the bus.
-
- Celine wants to go home, remove her.
-
- Remaining students in bus.
- Pierre Dupont (16) is in the bus.
- Hugot Badeaux (18) is in the bus.
-
- End of demo, free all resources.
- Removing student: Pierre Dupont
- Removing student: Hugot Badeaux
一切正如我们预期的那样,我们实现了对链表的添加、遍历、导出和删除。
最后,使用 list.h 时需要注意代码的可读性,先看看下面这个例子:
- typedef struct school {
- struct list_head list_students;
- struct list_head list_teachers;
- struct list_head list_guards;
- struct list_head list_classrooms;
- struct list_head list_bus;
- } school_t;
这个结构体的本意很明显,就是想包含一所学校内所有的人员和器材等等。但是单凭这样一个结构体,我们无法知道每一个链表内元素的具体类型。尤其是当你把一个项目丢给新接手的开发人员时,他看到这样一个结构体,会比较头疼。而且很多项目内,结构体的名字并非都那么浅显易懂。
当他想使用宏 list_for_each_entry
或者 list_for_each_entry_safe
遍历链表时,如果没有具体注解,他甚至不知道该用什么结构体类型。所以,一定要有详细的注解:
- typedef struct school {
- struct list_head list_students; /* struct student */
- struct list_head list_teachers; /* struct teacher */
- struct list_head list_guards; /* struct guard */
- struct list_head list_classrooms; /* struct classroom */
- struct list_head list_bus; /* struct bus */
- } s
综上所述,我个人的意见:list.h 很好用,但是要慎用。
- typedef struct student{
- char first_name[MAX_STRING_LENTH];
- char last_name[MAX_STRING_LENTGH];
- unsigned int age;
- struct list_head student_node;
- } student_t;
-
- //定义链表方法1: class
- student_t *class = NULL;
- struct list_head class;
- INIT_LIST_HEAD(&class);
-
- //定义链表方法2: bus
- student_t *bus = NULL;
- LIST_HEAD(bus);
原因如下:
- #define LIST_HEAD_INIT(name) { &(name), &(name) }
- #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
当然,如果你想在用户态使用list.h 可能不行, 用户态只能使用/usr/include/ 下的lib
所以,如果你想在用户态使用list.h ,需要保证有 /usr/include/linux/list.h
- #ll /usr/include/linux/list.h
- ls: cannot access /usr/include/linux/list.h: No such file or directory
如果你find到了, 你可以这样:
- cp -r /usr/include/linux{,.bak}
- #ln -sf /usr/src/kernels/3.10.0-327.xxxxxx.x86_64/include/linux /usr/include/linux
但是,这不是一种科学的方法, 因为你还会遇到很多依赖:
- #gcc -o stu stu.c -D__KERNEL__ -DMODULE -O -Wall
- In file included from /usr/include/linux/list.h:4:0,
- from stu.c:1:
- /usr/include/linux/types.h:5:30: fatal error: uapi/linux/types.h: No such file or directory
- #include <uapi/linux/types.h>
- ^
- compilation terminated.
最终办法,在自己的project里放一个list.h : http://www.cnblogs.com/muahao/p/8109733.html
- #cat simple_student.c
- #include "list.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define MAX_LENGTH 100
-
- typedef struct student {
- char first_name[MAX_LENGTH];
- char last_name[MAX_LENGTH];
- unsigned int age;
- struct list_head student_node;
- } student_t;
-
- struct list_head class;
- INIT_LIST_HEAD(&class);
- //LIST_HEAD(class);
- student_t *stu = NULL;
-
- student_t *make_student (const char *fn, const char *ln, unsigned int a) {
- student_t *stu = NULL;
-
- if ((stu = calloc(1, sizeof(struct student))) == NULL) {
- return NULL;
- }
-
- if (strlen(fn) > (MAX_LENGTH - 1)) {
- return NULL;
- }
-
- if (strlen(ln) > (MAX_LENGTH - 1)) {
- return NULL;
- }
-
- strcpy(stu->first_name, fn);
- strcpy(stu->last_name, ln);
- stu->age = a;
-
- return stu;
- }
-
-
- int main(){
- if ((stu = make_student("ahao","mu",22)) == NULL) {
- fprintf(stderr,"Failed to create muahao\n");
- return -1;
- }
- }
- 方法1 :
- struct list_head class;
- INIT_LIST_HEAD(&class);
-
- 方法2:
- LIST_HEAD(class);
在这里,我总是,使用方式1 的时候会提示如下错误:
- #gcc -o simple_student simple_student.c
- simple_student.c:16:16: error: expected declaration specifiers or ‘...’ before ‘&’ token
- INIT_LIST_HEAD(&class);
- ^
- #cat student.c
- #include "list.h"
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
-
- #define MAX_LENGTH 100
-
- typedef struct student {
- char first_name[MAX_LENGTH];
- char last_name[MAX_LENGTH];
- unsigned int age;
- struct list_head node_student;
- } student_t;
-
- student_t *make_student (const char *fn, const char *ln, unsigned int a) {
- student_t *stu = NULL;
-
- if ((stu = calloc(1, sizeof(struct student))) == NULL) {
- return NULL;
- }
-
- if (strlen(fn) > (MAX_LENGTH - 1)) {
- return NULL;
- }
-
- if (strlen(ln) > (MAX_LENGTH - 1)) {
- return NULL;
- }
-
- strcpy(stu->first_name, fn);
- strcpy(stu->last_name, ln);
- stu->age = a;
-
- return stu;
- }
-
-
- int main() {
- // Method 1
- //struct list_head class;
- //INIT_LIST_HEAD(&class);
-
- //Method 2
- LIST_HEAD(class);
-
- student_t *stu = NULL;
-
- //create student
- if ((stu = make_student("ahao","mu",22)) == NULL) {
- fprintf(stderr,"Failed to create muahao\n");
- return -1;
- }
-
- list_add_tail(&stu->node_student, &class);
-
- if ((stu = make_student("lianjie", "li", 23)) == NULL) {
- fprintf(stderr,"Failed to create li tom\n");
- return -1;
- }
-
- list_add_tail(&stu->node_student, &class);
-
- if ((stu = make_student("xiaolong", "li", 12)) == NULL) {
- fprintf(stderr, "Failed to create lixuehua\n");
- return -1;
- }
-
- list_add_tail(&stu->node_student, &class);
-
- / Print all students
-
- printf("------print all students-----\n");
-
- list_for_each_entry(stu, &class, node_student) {
- printf("First name:%s\n", stu->first_name);
- printf("Last name:%s\n", stu->last_name);
- printf("Age:%d\n", stu->age);
- }
-
-
- list bus
-
- LIST_HEAD(bus);
- printf("Moving all students to bus;\n");
- list_splice_init(&class, &bus);
- if (list_empty(&class)) {
- printf("No students in class\n");
- }
-
- printf("Print all bus students\n");
- list_for_each_entry(stu, &bus, node_student) {
- printf("%s %s %d", stu->first_name, stu->last_name, stu->age);
- }
-
- student_t *tmp = NULL;
-
- printf("muahao do not want go\n");
- list_for_each_entry_safe(stu, tmp, &bus, node_student) {
- if (strcmp(stu->first_name, "mu") == 0) {
- list_del(&stu->node_student);
- free(stu);
- }
- }
-
- printf("After muahao leave,students are: \n");
- list_for_each_entry(stu, &bus, node_student) {
- printf("%s %s %d\n",stu->first_name, stu->last_name, stu->age);
- }
-
- // end begin clean all students;
-
- list_for_each_entry_safe(stu, tmp, &bus, node_student) {
- printf("Removing students: %s %s \n", stu->first_name, stu->last_name);
- list_del(&stu->node_student);
- free(stu);
- }
-
- return 0;
- }
- #cat list.h
- /*
- * Copyright (C) 2012 Fusion-io. All rights reserved.
- *
- * This header was taken from the Linux kernel
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License v2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #ifndef _LINUX_LIST_H
- #define _LINUX_LIST_H
-
- #define LIST_POISON1 ((void *) 0x00100100)
- #define LIST_POISON2 ((void *) 0x00200200)
-
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
-
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
- /*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
- struct list_head {
- struct list_head *next, *prev;
- };
-
- #define LIST_HEAD_INIT(name) { &(name), &(name) }
-
- #define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
- static inline void INIT_LIST_HEAD(struct list_head *list)
- {
- list->next = list;
- list->prev = list;
- }
-
- /*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
- #ifndef CONFIG_DEBUG_LIST
- 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;
- }
- #else
- extern void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next);
- #endif
-
- /**
- * 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.
- */
- #ifndef CONFIG_DEBUG_LIST
- static inline void list_add(struct list_head *new, struct list_head *head)
- {
- __list_add(new, head, head->next);
- }
- #else
- extern void list_add(struct list_head *new, struct list_head *head);
- #endif
-
-
- /**
- * 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);
- }
-
- /*
- * 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 already!
- */
- 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.
- */
- #ifndef CONFIG_DEBUG_LIST
- static inline void list_del(struct list_head *entry)
- {
- __list_del(entry->prev, entry->next);
- entry->next = LIST_POISON1;
- entry->prev = LIST_POISON2;
- }
- #else
- extern void list_del(struct list_head *entry);
- #endif
-
- /**
- * list_replace - replace old entry by new one
- * @old : the element to be replaced
- * @new : the new element to insert
- * Note: if 'old' was empty, it will be overwritten.
- */
- static inline void list_replace(struct list_head *old,
- struct list_head *new)
- {
- new->next = old->next;
- new->next->prev = new;
- new->prev = old->prev;
- new->prev->next = new;
- }
-
- static inline void list_replace_init(struct list_head *old,
- struct list_head *new)
- {
- list_replace(old, new);
- INIT_LIST_HEAD(old);
- }
- /**
- * 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);
- }
-
- /**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
- static inline void list_move(struct list_head *list, struct list_head *head)
- {
- __list_del(list->prev, list->next);
- list_add(list, head);
- }
-
- /**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
- static inline void list_move_tail(struct list_head *list,
- struct list_head *head)
- {
- __list_del(list->prev, list->next);
- list_add_tail(list, head);
- }
-
- /**
- * list_is_last - tests whether @list is the last entry in list @head
- * @list: the entry to test
- * @head: the head of the list
- */
- static inline int list_is_last(const struct list_head *list,
- const struct list_head *head)
- {
- return list->next == head;
- }
-
- /**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
- static inline int list_empty(const struct list_head *head)
- {
- return head->next == head;
- }
-
- /**
- * list_empty_careful - tests whether a list is empty and not being modified
- * @head: the list to test
- *
- * Description:
- * tests whether a list is empty _and_ checks that no other CPU might be
- * in the process of modifying either member (next or prev)
- *
- * NOTE: using list_empty_careful() without synchronization
- * can only be safe if the only activity that can happen
- * to the list entry is list_del_init(). Eg. it cannot be used
- * if another CPU could re-list_add() it.
- */
- static inline int list_empty_careful(const struct list_head *head)
- {
- struct list_head *next = head->next;
- return (next == head) && (next == head->prev);
- }
-
- static inline void __list_splice(struct list_head *list,
- struct list_head *head)
- {
- struct list_head *first = list->next;
- struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
- }
-
- /**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
- static inline void list_splice(struct list_head *list, struct list_head *head)
- {
- if (!list_empty(list))
- __list_splice(list, head);
- }
-
- /**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
- static inline void list_splice_init(struct list_head *list,
- struct list_head *head)
- {
- if (!list_empty(list)) {
- __list_splice(list, head);
- INIT_LIST_HEAD(list);
- }
- }
-
- /**
- * 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) \
- container_of(ptr, type, member)
-
- /**
- * list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop cursor.
- * @head: the head for your list.
- */
- #define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); \
- pos = pos->next)
-
- /**
- * __list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop cursor.
- * @head: the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
- #define __list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
- /**
- * list_for_each_prev - iterate over a list backwards
- * @pos: the &struct list_head to use as a loop cursor.
- * @head: the head for your list.
- */
- #define list_for_each_prev(pos, head) \
- for (pos = (head)->prev; pos != (head); \
- pos = pos->prev)
-
- /**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos: the &struct list_head to use as a loop cursor.
- * @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_entry - iterate over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
- #define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
- /**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
- #define list_for_each_entry_reverse(pos, head, member) \
- for (pos = list_entry((head)->prev, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.prev, typeof(*pos), member))
-
- /**
- * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
- * @pos: the type * to use as a start point
- * @head: the head of the list
- * @member: the name of the list_struct within the struct.
- *
- * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
- */
- #define list_prepare_entry(pos, head, member) \
- ((pos) ? : list_entry(head, typeof(*pos), member))
-
- /**
- * list_for_each_entry_continue - continue iteration over list of given type
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Continue to iterate over list of given type, continuing after
- * the current position.
- */
- #define list_for_each_entry_continue(pos, head, member) \
- for (pos = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
- /**
- * list_for_each_entry_from - iterate over list of given type from the current point
- * @pos: the type * to use as a loop cursor.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing from current position.
- */
- #define list_for_each_entry_from(pos, head, member) \
- for (; &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member))
-
- /**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
- #define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
- /**
- * list_for_each_entry_safe_continue
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
- */
- #define list_for_each_entry_safe_continue(pos, n, head, member) \
- for (pos = list_entry(pos->member.next, typeof(*pos), member), \
- n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
- /**
- * list_for_each_entry_safe_from
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate over list of given type from current point, safe against
- * removal of list entry.
- */
- #define list_for_each_entry_safe_from(pos, n, head, member) \
- for (n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
- /**
- * list_for_each_entry_safe_reverse
- * @pos: the type * to use as a loop cursor.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
- */
- #define list_for_each_entry_safe_reverse(pos, n, head, member) \
- for (pos = list_entry((head)->prev, typeof(*pos), member), \
- n = list_entry(pos->member.prev, typeof(*pos), member); \
- &pos->member != (head); \
- pos = n, n = list_entry(n->member.prev, typeof(*n), member))
-
- #endif
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。