Linux内核数据结构之链表

来源:互联网 发布:python 顶级黑客 编辑:程序博客网 时间:2024/05/22 10:28

链表

在学习《Linux内核设计与实现》中链表结构时,对<scripts\kconfig\list.h>(我看的内核是2.6的,在其他版本对链表的定义可能不在这个目录中)中的宏定义:container_of()很困惑,所以google一番,现记录自己对其的理解:

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

宏定义的三个参数的含义分别为:

type:一般是个结构体,也就是包含用户数据和链表节点的结构体

ptr:是指向type中链表节点的指针

member:是type中定义链表节点时用的名字

比如:

struct student{    int id;    char* name;    struct list_head list;};
  • type是struct student
  • ptr是指向struct list_head的指针,也就是指向member类型的指针
  • member就是list

对于container_of宏:

// 步骤1:将数字0强制转型为type*,然后取得其中的member元素((type *)0)->member  // 相当于((struct student *)0)->list// 步骤2:定义一个临时变量__mptr,并将其也指向ptr所指向的链表节点const typeof(((type *)0)->member)*__mptr = (ptr);// 步骤3:计算member字段距离type中第一个字段的距离,也就是type地址和member地址之间的差// offset(type, member)也是一个宏,定义如下:#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)// 步骤4:将__mptr的地址 - type地址和member地址之间的差// 其实也就是获取type的地址
步骤1很好理解,就是强制类型转换。

步骤2中的typeof()的用法说明:

//把y定义成x指向的数据类型:typeof(*x) y;

步骤3:(TYPE *)0,将 0 强制转换为 TYPE 型指针,记 p = (TYPE *)0,p是指向TYPE的指针,它的值是0。那么 p->MEMBER 就是 MEMBER 这个元素了,而&(p->MEMBER)就是MENBER的地址,而基地址为0,这样就巧妙的转化为了TYPE中的偏移量。再把结果强制转换为size_t型的就OK了,size_t其实也就是int。
typedef __kernel_size_t  size_t;
typedef unsigned int __kernel_size_t;   

步骤4就是为了获得type的地址。

通过container_of()宏,我们定义一个简单的函数就可以返回包含list_head的父类型结构体:

#define list_entry(ptr, type, member) \container_of(ptr, type, member)
因为我们获得一个指向链表结构的指针通常是无用的,我们要操作的是用户数据,是一个指向包含list_head的结构体指针,如之前的student结构体。而通过宏定义container_of()就可以让我们获得该结构体的首地址。






原创粉丝点击