linux内核中container_of宏的分析
最近在学习linux,将自己所学到的分享给大家,自己还是个新手,如果有什么错误希望大家能指出,谢谢!
先看一下container_of宏,在linux目录include/linux/Kernel.h文件里,如下:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
这是一个有三个参数的宏,ptr代表结构体某个成员的地址,type代表结构体的类型,member标志结构体成员参数。如果我们知道这三个参数,就可以推导出该结构体的首地址,这就是container_of的作用,现在来分析一下:
首先将0作为一个type类型的指针,相当于type * p = 0;一个指向地址0的指针,
typeof((type *)0->member)则为获取结构体成员member 的类型,是char?short?还是int?
const typeof( ((type *)0)->member ) *__mptr = (ptr)则是用成员member的类型再定义一个指针 __mptr,等于ptr,加上const,表示只读变量,不可修改。
(type *)( (char *)__mptr - offsetof(type,member) );
第二句又是什么意思呢?先不管它,先看看这个东东:
offsetof(type,member);
这也是一个非常有意思的宏,在/include/linux/Stddef.h文件中,如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
这里的TYPE指结构体类型,MEMBER指结构体成员变量名,这个宏的作用就是得到结构体成员地址与结构体首地址的相对偏移量。
size_t 就是 unsigned int
(TYPE* 0) 定义一个指向0地址的TYPE结构体类型的指针;
这里的 “ & ”,,不是size_t与上((TYPE *0)->MEMBER),而是对变量MEMBER取地址,相当于&a; 对变量a取地址,在把它转化为(unsigned int) 类型,这个宏,设计的非常巧妙。
接下来再来看第二句:
(type *)( (char *)__mptr - offsetof(type,member) );
结构体成员指针__mptr,减去与首地址的偏移地址,那不就是结构体的首地址吗?
在将这个地址转化为该结构体类型的指针,就得到了该结构体的指针。完美!
如果你知道结构体成员的地址,结构体类型,以及结构体的变量名,想知道该结构体指针,那就用它吧。