Linux 内核链表的使用

这里写自定义目录标题


Linux内核链表的核心思想是:在用户自定义的结构A中声明list_head类型的成员p,这样每个结构类型为A的变量a中,都拥有同样的成员p,如下:

struct A{

int property;

struct list_head p;

}

其中,list_head结构类型定义如下:

struct list_head {

struct list_head *next,*prev;

};

list_head拥有两个指针成员,其类型都为list_head,分别为前驱指针prev和后驱指针next。

假设:

(1)多个结构类型为A的变量a1…an,其list_head结构类型的成员为p1…pn

(2)一个list_head结构类型的变量head,代表头节点

使:

(1)head.next= p1 ; head.prev = pn

(2) p1.prev = head,p1.next = p2;

(3)p2.prev= p1 , p2.next = p3;

(n)pn.prev= pn-1 , pn.next = head

以上,则构成了一个循环链表。

因p是嵌入到a中的,p与a的地址偏移量可知,又因为head的地址可知,所以每个结构类型为A的链表节点a1…an的地址也是可以计算出的,从而可实现链表的遍历,在此基础上,则可以实现链表的各种操作。

下面是从linux内核中移植出来的简单链表,list.h和list.c:

list.h:


#ifndef _INIT_LIST_H_
#define _INIT_LIST_H_
 
#ifndef offsetof
/* Offset of member MEMBER in a struct of type TYPE. */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
 
struct listnode
{
    struct listnode *next;
    struct listnode *prev;
};
 
#define node_to_item(node, container, member) \
    (container *) (((char*) (node)) - offsetof(container, member))
 
#define list_declare(name) \
    struct listnode name = { \
        .next = &name, \
        .prev = &name, \
    }
 
#define list_for_each(node, list) \
    for (node = (list)->next; node != (list); node = node->next)
 
#define list_for_each_reverse(node, list) \
    for (node = (list)->prev; node != (list); node = node->prev)
 
void list_init(struct listnode *list);
void list_add_tail(struct listnode *list, struct listnode *item);
void list_remove(struct listnode *item);
 
#define list_empty(list) ((list) == (list)->next)
#define list_head(list) ((list)->next)
#define list_tail(list) ((list)->prev)

#endif

list.c:


#include "list.h"
 
void list_init(struct listnode *node)
{
    node->next = node;
    node->prev = node;
}
 
void list_add_tail(struct listnode *head, struct listnode *item)
{
    item->next = head;
    item->prev = head->prev;
    head->prev->next = item;
    head->prev = item;
}
 
void list_remove(struct listnode *item)
{
    item->next->prev = item->prev;
    item->prev->next = item->next;
}

测试代码list_test.c:

#include
#include
#include "list.h"
 
#define STUDENT_FREE_MEMORY
 
//声明链表节点
typedef struct {
	int id;
	char *name;
	struct listnode _list;
}student;
 
//遍历函数指针
typedef void (*student_foreach_fun)(student *stu,void *data);
 
 
//声明链表
static list_declare(student_list);
 
//添加节点
int student_add(struct listnode *list,student *stu)
{
	list_init(&stu->_list);
	list_add_tail(list,&stu->_list);	
}
 
//删除节点,释放节点空间
int student_del(struct listnode *list,int id)
{
	struct listnode *node;
	student *stu;
	list_for_each(node,list){
		stu = node_to_item(node,student,_list);
		if(id == stu->id){
			printf("list_del, id:%d,name:%s\n",stu->id,stu->name);
			list_remove(node);
#ifdef STUDENT_FREE_MEMORY	
			//释放节点空间
			free(stu);
			stu = NULL;
#endif
			return 1;
			
		}
		
	}
 
	return 0;
}
 
//节点遍历
void student_foreach(struct listnode *list,student_foreach_fun fun,void *data)
{
	struct listnode *node;
	student *stu;
	list_for_each(node,list){
		stu = node_to_item(node,student,_list);
		fun(stu,data);
	}
 
}
 
//打印节点信息
void student_print(student *stu,void *data)
{
	printf("id:%d,name:%s\n",stu->id,stu->name);
}
 
int main()
{
	int i,len;
	student *stu;
	char *stu_name[]={"tonny","andy","michael","leslie","john"};
	
	
	len = sizeof(stu_name)/sizeof(stu_name[0]);
	//添加节点
	for(i=0;iid = i + 1;
		stu->name = stu_name[i];
 
		student_add(&student_list,stu);
	}
 
	//打印所有节点
	student_foreach(&student_list,student_print,(void *)0);
	
	//删除节点
	student_del(&student_list,1);
	student_foreach(&student_list,student_print,(void *)0);
 
	//删除节点
	student_del(&student_list,5);
	student_foreach(&student_list,student_print,(void *)0);
	
	return 0;
	
 
}

Makefile:


TARGET=list_test
SRC=list_test.c list.c
#SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
CFLAGS=-g -Wall -o
 
$(TARGET):$(SRC)
	gcc $(SRC) $(CFLAGS) $(TARGET)
clean:
	rm $(OBJ) $(TARGET)


作者:xnwyd
来源:CSDN
原文:https://blog.csdn.net/xnwyd/article/details/7359373

你可能感兴趣的:(嵌入式Linux)