c语言高级应用 list_entry 链表获取所在结构体的首地址
为了代码简介高效,可以方便的被多个链表连接起来,而且这个链表可以很方便的被各种不同类型数据域复用,我们实现单双链表时候(链表节点中不需要数据域),可以像下面这样子:typedef struct List{ struct List* next; struct List* pre; //注:这里面没有数据域}List_t;typedef struct Student{ char name; int age; int high; //该学生可能存在于多个链表中,比如在男生链表,又在班级链表 List_t node1; List_t node2; }Student_t;/***@fn ListInsert*@brief链表插入新节点*@paramnewNode 新节点*@paramposNode 插入位置节点*@return 无*@note 默认插入到posNode后面*/void ListInsert(List_t* newNode, List_t* posNode){ newNode->pre = posNode; newNode->next = posNode->next; posNode->next->pre = newNode; newNode->next = newNode;}void main(){ Student_t s1,s2; //s1和s2连接成链表1 ListInsert(&(s1.node1), &(s2.node1)); //s1和s2连接成另一个链表2 ListInsert(&(s1.node2), &(s2.node2));}此时,当我们得到了s1.node1的地址 (设为p1) 时候,现在想拿到s1的首地址(s1.node1所在结构体),怎么办呢,这时候,过程如下:
1. 获得Student结构体首地址和它的成员node1的地址差,如下
p = &( (Student*)0 -> node1 ) //思想:假设现在Student结构体的首地址假设为0,此时成员node1的地址就是相对偏移啦
2. 拿s1.node1的地址减去得到的地址差即可
p1 - p 就得到了我们想要的Student结构体的首地址。这个就是list_enty宏定义的实现原理,完整实现如下:
#define list_entry(ptr, type, member) \container_of(ptr, type, member)#define container_of(ptr, type, member) ((type *)((u8*)ptr - offsetof(type,member)))#define offsetof(type, member) ((u32) &((type *)0)->member)Linux系统内核中的链表就是这样子实现滴喔
https://blog.51cto.com/u_13682052/4761520
页:
[1]