C语⾔宏函数container of()简介
在linux 内核编程中,会经常见到⼀个宏函数container_of(ptr,type,member), 但是当你通过追踪源码时,像我们这样的⼀般⼈就会绝望了(这⼀堆都是什么呀?函数还可以这样定义怎么还有0呢哎,算了,还是放弃吧。。。)。这就是内核⼤佬们厉害的地⽅,随便两⾏代码就让我们怀疑⼈⽣,凡是都需要⼀个过程,慢慢来吧。
其实,原理很简单:已知结构体type的成员member的地址ptr,求解结构体type的起始地址。
type的起始地址 = ptr - size (这⾥需要都转换为char *,因为它为单位字节)。
到此,该函数已经讲完,是不是很简单其实也不是,这⾥并没有提到size如何计算,⽽令我们头晕的正是这⾥。
好吧,先上container of函数原型:
#define container_of(ptr, type, member) ({              \
const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
(type *)( (char *)__mptr - offsetof(type,member) );})
其次为 offserof 函数原型:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
怎么样,是不是很炫?好吧,下⾯开始揭开⾯纱:
(⼀)0 指针的使⽤(⾃⼰给的名字,不知有⽊问题)
让事实说话:
#include<stdio.h>
struct test
{
char i ;
自定义函数怎么用c语言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
什么意思看到了吧,⾃定义的结构体有三个变量:i,j,k。因为有字节对齐要求,所以该结构体⼤⼩为4bytes * 3 =12 bytes.  ⽽&((struct test *)0)->k 的作⽤就是求 k到结构体temp起始地址的字节数⼤⼩(就是我们的size)。在这⾥0被强制转化为struct test *型,它的作⽤就是作为指向该结构体起始地址的指针,就是作为指向该结构体起始地址的指针,就是作为指向该结构体起始地址的指针,⽽&
((struct test *)0)->k的作⽤便是求k到该起始指针的字节数。。。其实是求相对地址,起始地址为0,则&k的值便是size⼤⼩(注:打印时因为需要整型,所以有个int强转)所以我们便可以求我们需要的 size 了。好吧,⼀不⼩⼼把 offsetof()函数的功能给讲完了:::
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
这次再看就顺眼了吧(底层为什么是这样我还是不懂。。。只知道这样确实可以),所以offsetof()的作⽤就是求我们梦寐以求的size, 并以size_t形式返回(size_t:⽆符号整型)。
(⼆)内核编程的严谨性
#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);
它的作⽤是什么呢?其实没什么作⽤(勿喷勿喷,让我把话说完),但就形式⽽⾔ _mptr = ptr,  那为什么要要定义⼀个⼀样的变量呢其实这正是内核⼈员的⽜逼之处:如果开发者使⽤时输⼊的参数有问题:ptr与member类型不匹配,编译时便会有warnning,但是如果去掉改⾏,那个就没有了,⽽这个警告恰恰是必须的(防⽌出错有不知道错误在哪⾥)。。。这严谨性可以吧
typeof( ((type *)0)->member )
它的作⽤是获取member的类型仅此⽽已。⾄此基本结束
(三)总结
container_of(ptr, type,member)函数的实现包括两部分:
1.判断ptr 与 member 是否为同意类型
2.计算size⼤⼩,结构体的起始地址 = (type *)((char *)ptr - size)  (注:强转为该结构体指针)
现在我们知道container_of()的作⽤就是通过⼀个结构变量中⼀个成员的地址到这个结构体变量的⾸地址。
container_of(ptr,type,member),这⾥⾯有ptr,type,member分别代表指针、类型、成员。
到此这篇关于C语⾔宏函数container of()简介的⽂章就介绍到这了。希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。