解释使用union的循环双向链表实现

时间:2018-04-04 04:34:43

标签: c pointers doubly-linked-list

我在解释这个双重链接列表时遇到了一些麻烦:

struct _dnode {
    union {
        struct _dnode *head;
        struct _dnode *next;
    };
    union {
        struct _dnode *tail;
        struct _dnode *prev;
    };
};

typedef struct _dnode sys_dlist_t;
typedef struct _dnode sys_dnode_t;

此列表中还定义了其他函数,例如查找给定节点是否为列表的头部:

static inline int sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node)
{
    return list->head == node;
}

现在,我的问题是 -

(i)为什么我们需要一个工会?那也是,以这种特定的方式?

(ii)如何将列表中的listnode作为相同类型的指针? (见typedef声明)

(iii)如果我宣布这种类型的清单,即。 data_node项将是sys_dlist_t类型的元素:

struct data_node{
    sys_dnode_t node;
    int data = 0;
} data_node[2];

我宣布一个节点:

sys_dnode_t *node = NULL;

然后如果我想迭代我的列表以检查data元素的data_node是否匹配,则说明数字3.我可以通过类型转换node(其中当前是指向sys_dnode_t类型的指针的类型为data_node的指针?

现在,在代码中,这已经完成,它就像:

if (((struct data_node *)node)->data == 3) {
    break;
}

这令我感到困惑。我可能错过了一些代码来解决这个问题,所以如果您需要更多信息,请告诉我。我们可以对node指针进行类型转换以指向包含node的某个结构,然后访问该结构的其他数据吗?这是如何工作的?

编辑1: 关于此列表的更多信息:

"这些列表应该被初始化,使得head和tail指针都指向列表本身。以这种方式初始化列表简化了向列表添加节点和从列表中删除节点的过程。"

初始化如下:

static inline void sys_dlist_init(sys_dlist_t *list)
{
    list->head = (sys_dnode_t *)list;
    list->tail = (sys_dnode_t *)list;
}

1 个答案:

答案 0 :(得分:1)

  

(i)为什么我们需要一个工会?那也是,以这种特定的方式?

这么方便,因为这个列表是循环的。列表结构是列表中的伪节点。因此,可以将节点视为列表结构和列表中的节点。

另一个定义可能是:

union _dnode {
    struct {
        union _dnode *head;
        union _dnode *tail;
    };
    struct {
        union _dnode *next;
        union _dnode *prev;
    };
};

typedef union _dnode sys_dlist_t;
typedef union _dnode sys_dnode_t;
  

(ii)为什么列表的列表和节点都将成为相同类型的指针? (参见typedef声明)

这样做也很方便,因为这些指针在内存中引用相同的结构。

  

(iii)如果我宣布这种类型的清单,即。 data_node项将是sys_dlist_t类型的元素...我可以通过类型转换节点(当前是一个类型为sys_dnode_t的指针)来指向类型为data_node的指针吗?

你可以,因为指向结构中第一个字段的指针和指向结构的指针是相同的。

节点字段不一定是第一个,但是简单的类型转换不能做到这一点。例如:

struct list_elem {
    int foo;
    char *bar;
    ...
    sys_dnode_t siblings;
};

sys_dnode_t *node;
struct list_elem *elem;

elem = (struct list_elem *)((char *)node - offsetof(struct list_elem, siblings));

或者如果你定义宏:

#define object_of(_ObjectT,_Field,x) \
    ((_ObjectT *)((char *)(x) - offsetof(_ObjectT,_Field)))

elem = object_of(struct list_elem, siblings, node);