0
点赞
收藏
分享

微信扫一扫

【Linux】list.h中链表的结构与访问方式(与双循环链表对比)

千白莫 2022-03-17 阅读 43

在linux内核中有一个list.h头文件。
它采用有头节点双向循环链表的方式,很优雅的支持了诸多链表操作。
本文意在辅助理解list.h中最核心的部分——内核链表如何定义 & 如何访问下一个数据。

内核链表的使用 vs 双循环链表

  • 使用正常结构体:
    指针指向最外层的结构体,访问数据时访问的是结构体内部的数据元素
    使用正常结构体:指针指向最外层的结构体,访问数据时访问的是结构体内部的元素
struct Node{
	//声明一个数据 可为结构体
	struct Node *next; //指向下一个结点的指针
	struct Node *prev; //指向前一个结点的指针
}
  • 使用内核结构体:
    在内核结构体外面套一层用于存储数据,
    指针指向内核结构体,访问数据时需先计算外部结构体的位置,在进行访问(详见下文)。
    在这里插入图片描述
这是list.h 中定义的一个list_head结构体,暂且称之为内核结构体。

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

内核结构体中只有两个指针,那我们在使用时,数据该如何存储呢?
显然,不能直接改动list.h中的结构体,因此我们使用时需要在内核结构体外部套一层用来存储数据(暂且称之为外部结构体)。

在使用时在内核结构体外套一层,用来存储数据
struct Node{
    int number;    想存储的数据,此处以整型为例
    struct list_head list;    list.h中定义的结构体
}

内核结构体访问数据

内核结构体访问数据时,只能找到要访问的内核结构体。

我们知道,结构体只能找到自己内部的元素。那如何找到套在外面的数据呢?

这就需要通过container_of**(ptr, type, member) (list.h提供的宏定义)来计算外部结构体位置。

找到外部结构体位置后,我们就能访问它内部的数据元素啦~

"list.h"中定义的 计算外部结构体位置的宏
#define container_of(ptr, type, member) ({			\
	const typeof(((type *)0)->member) * __mptr = (ptr);	\
	(type *)((char *)__mptr - offsetof(type, member)); })

内核结构体为啥存在

内核结构体的访问显然比常规的结构体要复杂。

但由于内核无法预先得知需要存储数据的数据结构,为保证其可扩展性,只能采用内嵌的方式。

举报

相关推荐

0 条评论