湛蓝之海 发表于 2021-12-7 17:14:37

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]
查看完整版本: c语言高级应用 list_entry 链表获取所在结构体的首地址