代码之家  ›  专栏  ›  技术社区  ›  nj2237 Rowland Ogwara

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

  •  0
  • nj2237 Rowland Ogwara  · 技术社区  · 8 年前

    我在解释这个双链接列表时遇到了一些问题:

    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)为什么 list node 列表中的将是相同类型的指针?(参见 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\u节点 元素匹配,比如数字3。我可以用打字的方式吗 节点 (当前是指向类型的指针 sys_dnode_t )指向类型的指针 data\u节点 ?

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

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

    这让我困惑。我可能遗漏了一些代码来解决这个问题,所以如果您需要更多信息,请告诉我。我们可以打字吗 节点 指向某个结构的指针,该结构包含 节点 然后访问结构的其他数据?这是如何工作的?

    编辑1: 此列表中没有更多信息:

    “应初始化列表,使头指针和尾指针都指向列表本身。以这种方式初始化列表可简化向列表中添加或从列表中删除节点的过程。”

    初始化如下:

    static inline void sys_dlist_init(sys_dlist_t *list)
    {
        list->head = (sys_dnode_t *)list;
        list->tail = (sys_dnode_t *)list;
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   freestyle    6 年前

    (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\u node项将是sys\u dlist\t类型的元素。。。我可以通过将node(当前是sys\u dnode\u t类型的指针)类型转换为data\u 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 objectof(_ObjectT,_Field,x) \
        ((_ObjectT *)((char *)(x) - offsetof(_ObjectT,_Field)))
    
    elem = objectof(struct list_elem, siblings, node);