为什么TAILQ_REMOVE没有重置头指针?

时间:2013-10-02 18:46:08

标签: c queue

我在一些我没写过的代码中追踪了一些奇怪的Coverity错误。在一种情况下,我们在循环中使用TAILQ_FIRST和TAILQ_REMOVE,如下所示:

while (!TAILQ_EMPTY(&queue))
{
    item* entry = TAILQ_FIRST(&queue);
    TAILQ_REMOVE(&queue, entry, next);
    free(entry);
}

Coverity抱怨很多,说我是双重解脱。但是,查看TAILQ_REMOVE,这可能是正确的:(在我的Linux机器上/usr/include/x86_64-linux-gnu/sys/queue.h

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

与其他一些相关的宏不同,如果我删除头节点,我在这里看不到任何重置tqe_first的内容。因此,我会继续在循环中获取已删除的节点。

但我真的不明白发生了什么。尽管有Coverity警告,此代码似乎仍然有效。

在网上找到这方面的例子很困难。

1 个答案:

答案 0 :(得分:3)

这是有效的,因为tqe_prev是指向指针的指针。如果非空,则队列中的第一个元素将其tqe_prev字段初始化为tqe_first的地址。因此,如果要删除第一个元素,则取消引用它并分配给它,就像在宏的最后一行中一样,最终会设置tqh_first。 (通常,tqe_prev将具有前一节点的tqe_next指针的地址。)