I encounter the following code when I am learning data structures and algorithms in C++. It is from https://github.com/xtaci/algorithms/blob/master/include/double_linked_list.h line 194 to 206.
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#ifndef _MSC_VER
#define list_entry(ptr, type, member) \
(reinterpret_cast<type *>((char *)(ptr)-(char *)(&(reinterpret_cast<type *>(1)->member))+1))
#else
#define list_entry(ptr, ptrtype, member) \
(reinterpret_cast<ptrtype>((char *)(ptr)-(char *)(&(reinterpret_cast<ptrtype>(1)->member))+1))
#endif
The comment block says the functionality of this Marco is to get the struct for this entry. What puzzles me is the use of
reinterpret_cast<type *>(1)->member
What does it mean by converting 1 to (type *) and access its member?
* Thanks for the help in advance. If any part is not clear, I will edit it quickly. *
* More information * :
This Marco is used in the code to define new Marco
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
And an example usage of the new Marco is from https://github.com/xtaci/algorithms/blob/master/include/graph_defs.h line 45 to 51 as part of the destructor.
struct Adjacent {
struct Vertex v;
int32_t color; // color for searching
int32_t d; // discover time
int32_t f; // finish time
struct list_head v_head; // vertex list header
struct list_head a_node;
uint32_t num_neigh; // num of neighbours
Adjacent(uint32_t id):v(id) {
INIT_LIST_HEAD(&v_head);
num_neigh = 0;
}
~Adjacent() {
Vertex * v, *vn;
list_for_each_entry_safe(v, vn, &v_head, v_node){
list_del(&v->v_node);
delete v;
}
}
......
&(reinterpret_cast<type *>(1)->member)
this statement if something like Macro offsetof
, using to get the offset address of a member in the struct.
the tricky reinterpret_cast<type *>(1)
tells the compiler there is a type *
pointer whose address is 0x1
, then &(reinterpret_cast<type *>(1)->member)
gets the offset address of the member plus the original 0x1
I've used code below to verify it.
struct list_head {
struct list_head *next, *prev;
};
struct Vertex {
int x;
int y;
list_head v_node;
};
int main()
{
Vertex *v = (Vertex *) malloc(sizeof(Vertex));
printf("%p", &(reinterpret_cast<Vertex *>(1)->v_node));
return 0;
}
it prints 0x9
, exactly 2*sizeof(int) + 1
Personally I think using 1
instead of 0
can avoid compiler treats it as an invalid NULL pointer. So in the macro, the 1
is plus again in the tail.
The macro list_entry
can be used like this
int main()
{
Vertex *v = (Vertex *) malloc(sizeof(Vertex));
Vertex *w = list_entry(&(v->v_node), Vertex, v_node);
printf("%p\n%p\n", v, w);
return 0;
}
when we only have the pointer to list_head
we can use list_entry
to get the outer struct. In the above code, v
and w
points to the same area.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.