linux内核container_of宏解析

在看linux内核的源代码的时候,经常会看到一个宏,就是container_of,它的作用是由一个结构体的成员指针得到这个结构体的指针。看的多了,就想搞明白这是怎么个东西,打开source insight一看,这个宏定义在include/linux/kernel.h这个头文件里边,打开一看,定义如下
/**
 * 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) );})


这个宏有三个参数,ptr是结构体成员的指针,type是这个结构体的类型,member是成员的变量名。
就这三行的代码,让我想了半天,最后还去网上查了查,最后才搞明白了,不得不承认C语言真的是博大精深,而linux内核的源代码真的是C语言的圣堂,这么优秀(可以用惊天地泣鬼神来形容了)的代码,也就在这里能看到了。
首先看第一行,const typeof( ((type *)0)->member ) *__mptr = (ptr);
这一行就是把0强转为一个type类型的指针,这个类型的成员member来定义一个指针__mptr,__mptr的值就是传入的ptr的值。
再来看第二行,(type *)( (char *)__mptr - offsetof(type,member) );
这一行把上一行得到的__mptr的地址减去member在type里的偏移值,就是type的结构体的指针。
这个offsetof又是什么鬼!
经过查找,offset定义在linux/compiler.h头文件里,定义如下
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#endif /* __KERNEL__ */


如果定义了__compiler_offsetof宏,就是用编译器内建的__compiler_offsetof,如果编译器没有定义这个宏,就使用#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)这个宏。
这个宏把0强行转化为TYPE类型的指针,然后指向他的member成员,由于这个指针的基地址是0,所以他的member成员的地址就是在0的基础上加上member的前边的变量的字节数,就是member在type结构体里边的偏移。
真的很完美的解决,至少我是佩服的一塌糊涂。

你可能感兴趣的:(c,linux,源代码,kernel,C语言,宏)