揭开linux内核中container_of的神秘面纱linux
做者:程姚根,华清远见嵌入式学院讲师。web
在linux 内核中有一个大名鼎鼎的宏container_of(),这个宏是用来干吗的呢?咱们先来看看它在内核中是怎样定义的。spa
呵呵,乍一看不知道是什么东东。指针
咱们先来分析一下container_of(ptr,type,member),这里面有ptr,type,member分别表明指针、类型、成员。看一个例子:orm
Struct test
{
int i;
int j;
char k;
};
Struct test temp;ci
如今呢若是我想经过temp.j的地址找到temp的首地址就能够使用container_of(&temp.j,struct test,j);get
如今咱们知道container_of()的做用就是经过一个结构变量中一个成员的地址找到这个结构体变量的首地址。it
下面来看看比较复杂的内容:form
咱们用上面的struct test张展一下test
Const typeof(((struct test *)0)->j) * __mptr = (&temp.j);
其中,typeof是GNU C对标准C的扩展,它的做用是根据变量获取变量的类型。所以,上述代码的做用是首先使用typeof获取结构体成员j的类型为int,而后顶一个int指针类型的临时变量__mptr,并将结构体变量中的成员的地址赋给临时变量__mptr。
(struct test *)((char *)__mptr - offsetof(struct test,j));
接着咱们来看一下offsetof(struct test,j),他在内核中以下定义
展开(size_t)&((struct test *)0)->j,这是什么东东?
一开始也不明白,这里要感谢曹老师老师的热心帮助,一语惊醒梦中人,呵呵,能够是这样理解。
其中size_t是整型,那么咱们能够知道最终的结果是一个整形值,也就是j相对于0地址的偏移量。也许如今你会问,整出这么个玩意干吗,下面看个列子:
程序运行结果:
发现没有若是把第二个值 减去最后一个值,就能获得第一个值。
在回首一下它:
(struct test *)((char *)__mptr - offsetof(struct test,j));
是否是能够得到结构体变量temp的首地址呀,是否是太精妙了呀,linux内核中随随便便一个宏就有如此精妙,呵呵,想一想对linux了解很是多的牛人,还有很长一段路。