Linux循环链表队列,详解Linux内核之双向循环链表(一)(3)

--------------------list_empty_careful()--------- Static inline int list_empty_careful(const struct list_head *head) { struct list_head *next = head-next; return (next == head) (next == head-prev);

--------------------list_empty_careful()---------

Static inline int list_empty_careful(const struct list_head *head)

{

struct list_head *next = head->next;

return (next == head) && (next == head->prev);

}

分析:

1.只有一个头结点head,这时head指向这个头结点,head->next,head->prev指向head,即:head==head->next==head->prev,这时候list_empty_careful()函数返回1。

2. 有两个结点,head指向头结点,head->next,head->prev均指向后面那个结点, 即:head->next==head->prev,而head!=head->next,head!=head->prev. 所以函数将返回0

3.有三个及三个以上的结点,这是一般的情况,自己容易分析了。

注意:这里empty list是指只有一个空的头结点,而不是毫无任何结点。并且该头结点必须其head->next==head->prev==head

4.5链表合并

Linux还支持两个链表的拼接,提供给用户的具体函数是list_splice和list_splice_init:

--------------__list_splice()------------------

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()----------------

static inline void list_splice(struct list_head *list, struct list_head *head)

{

if (!list_empty(list))

__list_splice(list, head);

}

这种情况会丢弃list所指向的头结点,这是特意设计的,因为两个链表有两个头结点,要去掉一个头结点。只要list非空链,head无任何限制,该程序都可以实现链表合并。

-------------------list_splice_init()-----------------------------------

static inline void list_splice_init(struct list_head *list,

struct list_head *head)

{

if (!list_empty(list)) 0

{

__list_splice(list, head);

INIT_LIST_HEAD(list);

}

}

将一个链表的有效信息合并到另外一个链表后,重新初始化空的链表头。

5、获取宿主对象指针

如果需要有某种数据结构的队列,就在这种数据结构定义内部放上一个list_head数据结构。例如,建立数据结构foo链表的方式是,在foo的定义中,嵌入了一个list_head成员list。这里foo就是所指的"宿主"。

typedef struct foo {

struct list_head list;

};

但是,如何通过list_head成员访问到宿主结构项呢?毕竟list_head不过是个连接件,而我们需要的是一个"特定"的数据结构链表。

先介绍几个基本宏:offsetof、typeof、containerof

-------\linux\stddef.h-----offsetof()-----------

#define __compiler_offsetof(a,b)  __builtin_offsetof(a,b)

而__builtin_offsetof()宏就是在编译器中已经设计好了的函数,直接调用即可。

-------------------------------

#undef offsetof  //取消先前的任何定义,可以保证下面的定义生效

#ifdef __compiler_offsetof

#define offsetof(TYPE,MEMBER)  __compiler_offsetof(TYPE,MEMBER)

#else

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#endif

一共4步

1. ( (TYPE *)0 ) 0地址强制 "转换" 为 TYPE结构的指针;

2. ((TYPE *)0)->MEMBER   访问结构中的数据成员;

3.  &( ( (TYPE *)0 )->MEMBER)取出数据成员的地址;

4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型.巧妙之处在于将0转换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址;

例说明:

#include

typedef struct _test

{

char i;

int j;

char k;

}Test;

int main()

{

Test *p = 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值