container_of是linux内核中常用的一个宏,这个宏的功能是,根据某个结构体字段的指针,找到对应的结构体指针。
话不多说,先上源码:
/** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
第一个参数为指向结构体中的成员的指针,第二个参数为结构体类型,第三个参数为结构体成员的名字。
如图,一个结构体struct a中包含三个成员b,c,d,一个指向成员c的指针p_c,通过
container_of(p_c,
struct
a,
c
)就可以计算出指向c所在的结构体的指针p_a
原理说明:
这个宏的原理是结构体成员指针ptr,减去结构体成员与此结构体首地址的偏移量(这个偏移量由offsetof宏获得),就得出了结构体首地址。这个功能是由宏声明的第三行实现的。
那么宏声明的那二行是干什么用的呢?它仅仅是把ptr重新赋值给了__mptr,看似没用。实际上这里起到了给开发者提醒的功能。如果开发者传入的ptr指针指向的类型,与结构体中成员的类型不符,编译器在这里会打印一条warning,提示开发者可能存在的错误。
测试代码:
#include <stdio.h> #include <linux/kernel.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ const typeof ( ((type *)0)->member ) *__mptr = (ptr); (type *)( ( char *)__mptr - offsetof(type,member) );}) struct a { int b ; int c ; int d ; }; int main( int argc, char *argv[]) { struct a a_obj, *p_a; int *p_c; p_c = &a_obj. c ; p_a = container_of(p_c, struct a, c); printf ("a_obj addr:%x a_obj addr obtained by container_of: %x ", ( unsigned int )&a_obj, ( unsigned int )p_a); return 0; }
打印结果:
a_obj addr:bfffed98
a_obj addr obtained by container_of: bfffed98