侵入式链表
普通链表
学习数据结构的时候写的链表是下面这个样子的
typedef struct LNode
{
int data; /* 数据域 */
int num; /* 数据域 */
struct LNode *pre; /* 指向下一个结点 */
struct LNode *next; /* 指向上一个结点 */
}
侵入式链表
在 Linux
内核中链表是这样定义的
struct list_node
{
struct list_node *next; /* 指向下一个结点 */
struct list_node *prev; /* 指向上一个结点 */
};
typedef struct list_node list_t; /* 链表类型 */
在使用的时候是这样定义的
struct object
{
uint8_t type; /* 类型 */
uint8_t flag; /* 标志 */
...
list_t list; /* 链表结点 */
};
每一个内核对象定义的时候,让结构体包含一个成员变量,这个成员变量是一个通用的链表结点。
二者区别
普通的链表和侵入式链表的区别在于
- 普通的链表结点的指针域存放的是
下一个结点的内存首地址
- 侵入式链表结点的指针域存放的是
下一个结点的链接域成员变量的内存首地址
普通的链表有了结点的内存首地址之后,该结点的其它成员变量很轻松就可以访问到
那既然侵入式链表存放的是 下一个结点的链接域成员变量的内存首地址
,如果想获取下一个结点的所有成员变量该如何操作呢,这里就需要使用到 list_entry
这个宏了
list_entry
宏 list_entry
用来通过结构体的成员指针来返回整个结构体的地址,有了结构体的地址,那么结构体其它成员就可以访问到了
该宏的实现如下:
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
具体宏的解析参见:list_entry/container_of