C 解释使用union的循环双链表实现
我在解释这个双链接列表时遇到一些问题:C 解释使用union的循环双链表实现,c,pointers,doubly-linked-list,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
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)为什么列表的列表
和节点
都是相同类型的指针?(参见typedef
声明)
(iii)如果我声明此类类型的列表,即数据节点
项将是系统列表
类型的元素:
struct data_node{
sys_dnode_t node;
int data = 0;
} data_node[2];
我声明一个节点,这样:
sys_dnode_t *node = NULL;
然后,如果我想迭代我的列表,检查data\u节点的data
元素是否匹配,比如说,数字3。我可以通过将节点
(当前是指向typesys\u dnode\u t
的指针)键入指向type数据节点
的指针来实现这一点吗
现在,在代码中,这已经完成了,就像:
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;
}
(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)如果我声明此类类型的列表,即数据节点项将是系统列表类型的元素。。。我可以通过将节点(当前是指向sys\u dnode\u t类型的指针)类型转换为指向data\u节点类型的指针来实现这一点吗
可以,因为指向结构中第一个字段的指针和指向结构的指针是相同的
节点字段不必是第一个字段,但是简单的类型转换不能做到这一点。例如:
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);
对于caseiii
,data\u节点
结构是模拟C中继承的一种方式。您确定在sys\u dlist\u中,头是头是尾是头吗?@freestyle哦,您说得对。让我纠正一下,在循环双链接列表中,这样做非常方便,因为您可以将列表结构视为伪节点。但根据你的描述,我不明白这份清单是否是循环的。你能显示列表初始化吗?@freestyle我已经添加了初始化部分,如果我错了,请纠正我,但它看起来确实像一个圆形的dllow,谢谢你的详细解释,我现在很清楚了。因此,如果它不是第一个字段,那么我需要在键入它时使用offsetof
,对吗?是的。更多。如果它是第一个字段,则offsetof
也将起作用,因为offsetof
将为0。