linux内核数据结构中的链表实现可谓独树一帜。
普通的链表结构是在数据结构中嵌入链表指针
struct fox{
unsigned long tail_length;
unsigned long weight;
struct fox *next;
struct fox *prev;
}
而linux的实现则是将指针链表中嵌入数据结构
struct list_head{
struct list_head *next;
struct list_head *prev;
}
struct fox{
unsigned long tail_length;
unsigned long weight;
struct list_head list;
}
使用宏container_of()可以取出链表指针父结构中包含的任何变量。
#define container_of(ptr, type, member) ({
const typeof(((type *)0)->member) *__mptr = (ptr);
(type *)((char *)__mptr - offsetof(type, member));
})
/*
typeof()构造了一个与ptr同类型的__mptr指针,并将ptr的值赋给了__mptr;
然后用__mptr指针减去当前结构体成员在结构体中的偏移量即可。
*/
其中,ptr是指向当前结构体某一成员的指针,type是结构体名,member是ptr所指向的成员名。宏返回的是指向当前结构体类型起始地址的指针。
该宏定义中的offsetof()是另一个宏定义,可以求出结构体成员在结构体中的偏移值。
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/*
&(((TYPE *)0)->MEMBER)取出了MEMBER相对于0地址的偏移值,然后用(size_t)转换了数据类型。
*/
这里我主要存留两个疑问,一是在constainer_of()宏中,为什么要申请新的__mptr指针,而不是直接用原来的ptr指针减去偏移值。二是为什么可以定义(TYPE *)0这样的指针。