Linux内核数据结构之链表
2013-09-10 21:43
246 查看
链表
在学习《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()就可以让我们获得该结构体的首地址。
相关文章推荐
- Linux内核数据结构之链表
- linux内核数据结构之链表
- linux内核数据结构之链表【转】
- linux内核数据结构-顺序存储链表(1)
- linux内核数据结构之链表
- linux内核数据结构之链表
- Linux内核数据结构之链表
- linux内核数据结构之链表
- 【Linux内核数据结构】最为经典的链表list
- AT&T汇编语言与GCC内嵌汇编,Linux内核数据结构之链表
- Linux内核数据结构—链表
- linux内核数据结构---链表(1)
- linux内核2.6.28调度相关的数据结构分析
- Linux嵌入式 -- 内核 - 内核链表
- 深入分析 Linux 内核链表
- linux简单内核链表排序
- [精华]]Linux内核2.6.14源码分析-双向循环链表代码分析(转)
- 深入分析 Linux 内核链表
- 【内核数据结构】 内核链表分析
- 深入分析 Linux 内核链表