问题
I am having some trouble interpreting this 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;
And further functions are defined on this list, like, for example finding if given node is head of the list:
static inline int sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node)
{
return list->head == node;
}
Now, my questions are -
(i) Why would we need a union here? That too, in this specific way?
(ii) How come both the list
and node
of the list are going to be pointers of same type? (see typedef
declaration)
(iii) If I declare a list of such a type, ie. the data_node
items will be the elements of the sys_dlist_t
type:
struct data_node{
sys_dnode_t node;
int data = 0;
} data_node[2];
and I declare a node such that:
sys_dnode_t *node = NULL;
and then if I want to iterate over my list to check if the data
of the data_node
element matches say, a number 3. Can I do that by typecasting node
(which is currently a pointer to type sys_dnode_t
) to a pointer to type data_node
?
Now, in the code, this has been done, and it is like:
if (((struct data_node *)node)->data == 3) {
break;
}
This bewilders me. I may have missed some code to figure this out, so please tell me if you need more information. Can we typecast a node
pointer to point to some struct that contains node
and then access other data of the struct? How does this work?
EDIT 1: Few more info on this list:
"The lists are expected to be initialized such that both the head and tail pointers point to the list itself. Initializing the lists in such a fashion simplifies the adding and removing of nodes to/from the list."
The initialization is as follows:
static inline void sys_dlist_init(sys_dlist_t *list)
{
list->head = (sys_dnode_t *)list;
list->tail = (sys_dnode_t *)list;
}
回答1:
(i) Why would we need a union here? That too, in this specific way?
So convenient, since this list is cyclic. The list structure is a pseudo node in the list. Therefore, the node can be viewed as a list structure and as node in a list.
Another definition might be:
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) How come both the list and node of the list are going to be pointers of same type? (see typedef declaration)
This is also convenient to do, since these pointers refer to the same structure in memory.
(iii) If I declare a list of such a type, ie. the data_node items will be the elements of the sys_dlist_t type... Can I do that by typecasting node (which is currently a pointer to type sys_dnode_t) to a pointer to type data_node?
You can, because the pointer to the first field in the structure and the pointer to the structure are the same.
A node field need not be the first, but then a simple typecasting can not do that. For example:
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));
or if you define macro:
#define objectof(_ObjectT,_Field,x) \
((_ObjectT *)((char *)(x) - offsetof(_ObjectT,_Field)))
elem = objectof(struct list_elem, siblings, node);
来源:https://stackoverflow.com/questions/49642853/interpreting-circular-doubly-linked-list-implementation-which-uses-union