so true

心怀未来,开创未来!
随笔 - 160, 文章 - 0, 评论 - 40, 引用 - 0
数据加载中……

tailq中的TAILQ_FOREACH_REVERSE一些说明

这个东西之前就看过一次,看了半天才搞懂,结果今天看时又看不懂了,又折腾了好久才看清楚是咋回事。
最关键的就是(*(((struct headname *)((var)->field.tqe_prev))->tqh_last))),拆解开来就是:
1。((struct headname *)((var)->field.tqe_prev)) 这一步用于将上一个elm中的field结构中的tqe_next的地址取出来,其实也就是elm中field这个struct节点的地址(请注意到该struct中只有两个元素,而且该struct的结构与headname完全一致);
2。(@1->tqh_last) 这一步用于将上一个elm中的field中的第二个元素(即tqe_prev)的地址取出来,该地址就是上一个elm的上一个elm中的field的tqe_next的地址, 而该地址恰好指向的就是上一个elm的地址
3。(*@2) 这一步用于取出指向上一个elm的地址

呵呵,真tm够绕人的,其实在步骤1里面完全可以用elm中的field这个struct来进行强制类型转化,但是由于elm中的field这个struct是个定义在elm内部的而且没有名字的struct,因此无法显示的调用类似于(struct headname *)这样的强制类型转化,因此就只好用headname这个struct name来做这件事情了。

此外,**tqh_prev得到的其实是当前elm,*tqh_prev得到的是当前elm的指针,只有tqh_prev才能逃离当前elm的怪圈,指向上一个elm的field结构的第一个元素(也即整个field struct)的地址,紧接着从这里做文章又跳到了上一个elm的上一个elm的field struct里面,哈哈,够曲折的。

这个过程中,最精妙的莫过于那个强制类型转化了,其实本质上就是在从struct的第一个元素寻找第二个元素,其实完全可以用第一个元素的地址+4(32位系统,64位系统需要+8)就可以得到,但是这种做法可移植性太差,对于那种非pod的类型就不work了。

关于TAILQ的用法,可以man queue看到。

最后,贴上TAILQ的全貌<sys/queue.h>:
/*
 * Tail queue definitions.
 */
#define    _TAILQ_HEAD(name, type, qual)                    \
struct name {                                \
    qual type *tqh_first;        /* first element */        \
    qual type *qual *tqh_last;    /* addr of last next element */    \
}
#define TAILQ_HEAD(name, type)    _TAILQ_HEAD(name, struct type,)

#define    TAILQ_HEAD_INITIALIZER(head)                    \
    { NULL, &(head).tqh_first }

#define    _TAILQ_ENTRY(type, qual)                    \
struct {                                \
    qual type *tqe_next;        /* next element */        \
    qual type *qual *tqe_prev;    /* address of previous next element */\
}
#define TAILQ_ENTRY(type)    _TAILQ_ENTRY(struct type,)

/*
 * Tail queue functions.
 */
#define    TAILQ_INIT(head) do {                        \
    (head)->tqh_first = NULL;                    \
    (head)->tqh_last = &(head)->tqh_first;                \
} while (/*CONSTCOND*/0)

#define    TAILQ_INSERT_HEAD(head, elm, field) do {            \
    if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)    \
        (head)->tqh_first->field.tqe_prev =            \
            &(elm)->field.tqe_next;                \
    else                                \
        (head)->tqh_last = &(elm)->field.tqe_next;        \
    (head)->tqh_first = (elm);                    \
    (elm)->field.tqe_prev = &(head)->tqh_first;            \
} while (/*CONSTCOND*/0)

#define    TAILQ_INSERT_TAIL(head, elm, field) do {            \
    (elm)->field.tqe_next = NULL;                    \
    (elm)->field.tqe_prev = (head)->tqh_last;            \
    *(head)->tqh_last = (elm);                    \
    (head)->tqh_last = &(elm)->field.tqe_next;            \
} while (/*CONSTCOND*/0)

#define    TAILQ_INSERT_AFTER(head, listelm, elm, field) do {        \
    if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
        (elm)->field.tqe_next->field.tqe_prev =         \
            &(elm)->field.tqe_next;                \
    else                                \
        (head)->tqh_last = &(elm)->field.tqe_next;        \
    (listelm)->field.tqe_next = (elm);                \
    (elm)->field.tqe_prev = &(listelm)->field.tqe_next;        \
} while (/*CONSTCOND*/0)

#define    TAILQ_INSERT_BEFORE(listelm, elm, field) do {            \
    (elm)->field.tqe_prev = (listelm)->field.tqe_prev;        \
    (elm)->field.tqe_next = (listelm);                \
    *(listelm)->field.tqe_prev = (elm);                \
    (listelm)->field.tqe_prev = &(elm)->field.tqe_next;        \
} while (/*CONSTCOND*/0)

#define    TAILQ_REMOVE(head, elm, field) do {                \
    if (((elm)->field.tqe_next) != NULL)                \
        (elm)->field.tqe_next->field.tqe_prev =         \
            (elm)->field.tqe_prev;                \
    else                                \
        (head)->tqh_last = (elm)->field.tqe_prev;        \
    *(elm)->field.tqe_prev = (elm)->field.tqe_next;            \
} while (/*CONSTCOND*/0)

#define    TAILQ_FOREACH(var, head, field)                    \
    for ((var) = ((head)->tqh_first);                \
        (var);                            \
        (var) = ((var)->field.tqe_next))

#define    TAILQ_FOREACH_REVERSE(var, head, headname, field)        \
    for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));    \
        (var);                            \
        (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))

/*
 * Tail queue access methods.
 */
#define    TAILQ_EMPTY(head)        ((head)->tqh_first == NULL)
#define    TAILQ_FIRST(head)        ((head)->tqh_first)
#define    TAILQ_NEXT(elm, field)        ((elm)->field.tqe_next)

#define    TAILQ_LAST(head, headname) \
    (*(((struct headname *)((head)->tqh_last))->tqh_last))
#define    TAILQ_PREV(elm, headname, field) \
    (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))

posted on 2010-08-08 11:52 so true 阅读(3816) 评论(0)  编辑  收藏 所属分类: C&C++