Linux源码 list.h解析

Linux源码中include/linux/list.h封装了双向链表的数据结构。

网上实现双向链表的方式大抵相同,都是定义一个struct Node表示链表的节点,Node结构体包含指向节点数据的指针,和指向节点的next和pre指针:

1 struct Node {
2    void *data;
3    Node *next;
4    Node *pre;   
5 };

这种方式将存放的数据保存在链表的节点内部,结构图如下:

list.h的实现思路很有趣。上图中存放的数据(绿色部分),被Node节点封装,耦合度较高。存放的数据一定要保存在Node节点中,而且访问数据时需要经历一次Node *到Data *的跳转,可能会破坏cache,进行两次内存寻址。

而在list.h中,将链表最基本的数据成员(next和pre指针)封装在list_head结构体中。

struct list_head {
    struct list_head *next, *prev;
};

存放数据的结构体只需要将list_head结构体引入,即可作为链表的节点:

struct Data {
   ... // 存放的数据
   struct list_head list;  
};

这样数据即可脱离上个方式中Node的限制,只需要在结构体中存储next和pre指针即可作为链表的节点,达到解耦的目的。如下图(绿色部分是存储的数据):

当然实现这种存储方式也要解决一个问题:如何通过next指针或pre指针获取数据?

假设我们定义了以下结构体封装一个人的基本信息:

struct people {
    char name[20];
    int age;
    struct list_head list;
};

struct people p1,p2 ;
strcpy(p1.name, "Jack");
p1.age = 20;
strcpy(p2.name, "Judy");
p2.age = 18;

p1->pre = &p2;
p1->next = &p2;
p2->next = &p1;
p2->pre = &p1;

从p1开始遍历这个链表时,我们怎么获取p2的数据呢?

首先,我们通过p1->next得到了p2中list_head成员的地址。但是无法获取p2其他成员变量的地址。

list.h是通过offsetof和container_of宏来获取list_head的父结构体成员变量地址的:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define  container_of(ptr, type, member) ({    
          const typeof( ((type *)0)->member ) *__mptr = (ptr); 
          (type *)( (char *)__mptr - offsetof(type,member) );})

offsetof:获取成员变量相对于结构体的偏移量

 如offsetof(struct people, age),展开为:((size_t)&((struct people *)0)->age)

假设struct people的地址为0,那(struct people*)0->age的地址就是age相对于struct people的偏移量。

container_of:给定指向成员变量member的指针ptr,获取父结构体的地址

父结构体的地址其实就是 ptr - offsetof(TYPE, MEMBER)

首先,定义一个__mptr=ptr,__mptr的类型为const typeof(((type *)0)->member) *

再获取父结构体的地址:(type *) ((char *)__mptr = offsetof(type, number))

在list.h中,定义了list_entry宏,以此通过list_head地址获取父结构体的地址:

/**
 * 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.
 */
#define list_entry(ptr, type, member) 
    container_of(ptr, type, member)
原文地址:https://www.cnblogs.com/HadesBlog/p/14264933.html