container_of实现分析

宏 container_of在linux kernel内核中被广泛应用,它的作用是通过结构体成员的地址结构体成员的名字以及结构体类型获取结构体成员所在结构体的首地址,有点绕。

其定义为 

	#define container_of(ptr, type, member) ({			\
		const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
		(type *)( (char *)__mptr - offsetof(type,member) );})
其中ptr为结构体成员的地址,type为结构体类型,member为结构体成员的名字(不是变量名,是变量前的类型的名字)。

它经历了两个步骤:

第一:

const typeof( ((type *)0)->member ) *__mptr = (ptr);

这条语句声明了一个临时变量__mptr,它的类型应该是member的类型,但是我们只有member的名字而没有member的类型,因此我们需要根据member名字反推它的类型。

这里使用到了一个“虚拟指针”---0,将0强制转化为type*类型,这样0地址后面的一段区域就被认为包含了type的元素,因此就可以通过->符号来得到其中的成员member,再通过typeof()获取其类型即可。(我认为这里的“虚拟指针”---0不一定必须是0,也可以是1,2,3等其他值,因为它只是临时充当了一下索引介质。)    这样,我们就获得了一个类型与ptr指向变量的类型相同的指针__mpter,而它的值与ptr一样,因此,__mptr实际就已经被连接到了我们的目标结构体了。

第二:

(type *)( (char *)__mptr - offsetof(type,member) );})
使用__mpter减去一个offset值,而这个offset值就是__mptr所属的结构体成员在结构体内部的偏移地址,这样减法的结果就是找到了所在结构体的首地址。


而offsetof(type,member)又是什么呢?其实现为

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
它也用到了(TYPE*)0这个东西,通过将0地址转化为(TYPE*)再索引到结构体成员MEMBER,再对该成员取地址就得到了该结构体成员的地址,而由于我们结构体的首地址为---0,所以此时MEMBER的地址实际就是结构体成员MEMBER在结构体内的偏移量。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值