linux内核函数:container_of

Linux version: 4.14

Code link: Linux source code (v4.14) - Bootlin


1 函数原型

 对于 container_of  [ include/linux/kernel.h: 927 ]

/**
 * 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) ({				\
	void *__mptr = (void *)(ptr);					\
	BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&	\
			 !__same_type(*(ptr), void),			\
			 "pointer type mismatch in container_of()");	\
	((type *)(__mptr - offsetof(type, member))); })

其中 offsetof  [ include/linux/stddef.h: 19 ]

#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)

2 函数使用

container_of(ptr, type, member) 用于从包含在某个结构体中的指针获得结构体本身的指针,通俗地讲就是 通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。

① ptr 参数指结构体某成员变量的首地址(指针)

② type 参数表示结构体类型

③ member 参数表示结构体中的成员变量名

④ 函数返回指是结构体的首地址(指针)

说明:在 container_of 宏定义中,下面这行代码的结果就是该宏的返回值

((type *)(__mptr - offsetof(type, member)));

下面给出一个示例演示:

struct mystruct {
    int a;
    int b;
    int c;
};

struct mystruct temp;

int *p = &temp.a;

container_of(p, struct mystruct, a);

container_of(p, struct mystruct, a) 得到的就是 temp 变量的地址。

3 原理说明

#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)

(TYPE *)0 是将 0 强制转换成 TYPE 型指针,则该指针一定指向 0 地址(数据段基址)。
&((TYPE *)0)->MEMBER 这句话其实是 &(((TYPE *)0)->MEMBER) ,通过该指针访问 TYPE 的 MEMBER 成员并得到其地址。相对于结构体的起始地址 0 ,那么 &((TYPE *)0)->MEMBER 就是相对于起始地址之间的偏移量,这个偏移量对于所有的 TYPE 型变量都是成立的。offsetof(TYPE, MEMBER) 就表示这个偏移量。 

void *__mptr = (void *)(ptr);

由于 offsetof() 函数求得的是偏移字节数(size_t 类型),而 __mptr 是 void* 类型,当指针类型为 void* 时,其加减运算与普通整数没有区别。所以二者相减便可以得到TYPE变量的起始地址,最后通过 (type *) 类型转换,将该地址转换为 TYPE 类型的指针。

补充:size_t 是一种无符号整数数据类型,如果编译器是 32 位,那么它只是 unsigned int

4 参考

一文解析linux内核之链表操作 - 知乎 (zhihu.com)

linux中container_of - 牧野星辰 - 博客园 (cnblogs.com)

指针加减运算--void*的加减_void * +1_神童i的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vane Zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值