在学习C ++中的数据结构和算法时遇到以下代码。它来自https://github.com/xtaci/algorithms/blob/master/include/double_linked_list.h第194到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
注释块表示此Marco的功能是获取此条目的结构。让我困惑的是使用
reinterpret_cast<type *>(1)->member
将1转换为(类型*)并访问其成员是什么意思?
*提前感谢您的帮助。如果任何部分不清楚,我会快速编辑。 *
*更多信息* :
这个Marco在代码中用于定义新的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))
新Marco的示例用法是从https://github.com/xtaci/algorithms/blob/master/include/graph_defs.h第45行到第51行作为析构函数的一部分。
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;
}
}
......
答案 0 :(得分:1)
&(reinterpret_cast<type *>(1)->member)
此语句是否类似于宏offsetof
,用于获取结构中成员的偏移地址。
棘手的reinterpret_cast<type *>(1)
告诉编译器有一个type *
指针,其地址为0x1
,然后&(reinterpret_cast<type *>(1)->member)
获取成员的偏移地址加上原始{{1} }}
我已使用下面的代码进行验证。
0x1
它打印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;
}
,正好是0x9
我个人认为使用2*sizeof(int) + 1
而不是1
可以避免编译器将其视为无效的NULL指针。所以在宏观中,0
在尾部再次加上。
宏1
可以像这样使用
list_entry
当我们只有指向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;
}
的指针时,我们可以使用list_head
来获取外部结构。在上面的代码中,list_entry
和v
指向同一区域。