linux之list链表操作

文章转载请标注原文地址:http://blog.csdn.net/uranus_wm/article/details/11933201

linux驱动开发经常用到链表,在此总结一下链表相关操作:

1. 文件位置:/include/linux/type.h

linux定义的链表是双向循环链表,结构体类型定义如下:

struct list_head {
	struct list_head *next, *prev;
};

使用者一般在自己结构体内部包含一个list_head成员,例如:

struct s3c_pl330_chan {
	unsigned long			sdaddr;
	struct list_head		node;
	struct pl330_req		*lrq;
	struct list_head		xfer_list;
};

上面s3c_pl330_chan这个结构体内部有两个struct list_head类型成员,说明s3c_pl330_chan这个结构体会同时出现在两个链表中。

2. 直接用list_head类型子成员初始化链表,初始只有ch节点自己,prev和next指针域都指向自己:

struct s3c_pl330_chan *ch;

INIT_LIST_HEAD(&ch->xfer_list);

static inline void INIT_LIST_HEAD(struct list_head *list)
{
 list->next = list;
 list->prev = list;
}

使用宏定义LIST_HEAD建立一个名称为name的全局链表,初始只有一个head节点,prev和next指针域都指向自己:

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
 struct list_head name = LIST_HEAD_INIT(name)

/*建立链表chan_list*/

static LIST_HEAD(chan_list);

 

3. 添加链表节点,可加在链表头或尾部,删除和添加类似,这里不详细说明

ch = kmalloc(sizeof(*ch), GFP_KERNEL);
/*添加到链表头*/
list_add(&ch->node, &chan_list);
/*添加到链表尾*/
list_add_tail(&ch->node, &chan_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;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
 __list_add(new, head, head->next);
}

static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
 __list_add(new, head->prev, head);
}


4. 以上都比较容易理解,下面说说链表的使用:

struct s3c_pl330_chan *ch;
list_for_each_entry(ch, &chan_list, node)
	if (ch->id == id)
		return ch;

这段代码作用是:以ch类型作为父类型,node作为其子成员,以&chan_list为链表头头指针向next遍历,并返回ch类型指针

然后通过id来匹配是否是需要查找的节点

list_for_each_entry(pos, head, member)是一个for(初始条件;条件判断;块结束语句);循环

初始条件语句:通过list_entry获得链表chan_list之后的第一个节点,并返回父类型s3c_pl330_chan节点指针

条件判断语句:替换后就是 &ch.node != (&chan_list);如果当前s3c_pl330_chan父类型节点的node链表指针不是&chan_list头指针,说明链表还没有遍历完

块结束语句:pos指向当前节点的下一个节点

#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_entry实现:

#define list_entry(ptr, type, member) \
 container_of(ptr, type, member)
#define container_of(ptr, type, member) ({   \
 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
 (type *)( (char *)__mptr - offsetof(type,member) );})

主要就是container_of的定义,这个宏的作用是:已知成员member在type中的偏移地址和member在内存中的地址,获取父类型type的内存地址

可以理解有这么一个结构体,ptr是一个member类型的指针,指向member在内存中的地址

struct type {

member0;

member1; 

member;   //ptr是一个member类型的指针,指向member在内存中的地址

member3;

};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值