在linux 内核编程中,会经常见到一个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的一般人就会绝望了(这一堆都是什么呀? 函数还可以这样定义??? 怎么还有0呢??? 哎,算了,还是放弃吧。。。)。 这就是内核大佬们厉害的地方,随便两行代码就让我们怀疑人生,凡是都需要一个过程,慢慢来吧。
到此,该函数已经讲完,是不是很简单??? 其实也不是,这里并没有提到size如何计算,而令我们头晕的正是这里。
好吧,先上container of函数原型:
其次为 offserof 函数原型:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
怎么样,是不是很炫? 好吧,下面开始揭开面纱:
(一)0 指针的使用 (自己给的名字,不知有木问题)
让事实说话:
-
#include<stdio.h> -
struct test -
{ -
char i ; -
int j; -
char k; -
}; -
int main() -
{ -
struct test temp; -
printf("&temp = %p\n",&temp); -
printf("&temp.k = %p\n",&temp.k); -
printf("&((struct test *)0)->k = %d\n",((int)&((struct test *)0)->k)); -
}
编译运行,可以得到如下结果:
-
&temp = 0xbf9815b4 -
&temp.k = 0xbf9815bc -
&((struct test *)0)->k = 8
#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) );})
这里我们只看第二行:
const typeof( ((type *)0)->member ) *__mptr = (ptr);
它的作用是什么呢? 其实没什么作用(
typeof( ((type *)0)->member )
它的作用是获取member的类型仅此而已。至此基本结束
(三) 总结
container_of(ptr, type,member)函数的实现包括两部分:
1. 判断ptr 与 member 是否为同意类型