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\na_obj addr obtained by container_of: %x\n", ( unsigned int )&a_obj, ( unsigned int )p_a);
return 0;
}
打印结果:
a_obj addr:bfffed98
a_obj addr obtained by container_of: bfffed98