container_of(ptr, type, member)宏的作用 该宏的作用是通过结构体成员的地址和结构体类型推导出结构体的地址,type是指结构体的类型,member是成员在结构体中的名字,ptr是该成员在type结构体中的地址。
container_of(ptr, type, member)宏解析 在 linux 源码的 toolsincludelinuxkernel.h文件下,container_of()的定义如下:
#ifndef container_of/*** 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) ({ const typeof(((type *)0)->member) * __mptr = (ptr); (type *)((char *)__mptr - offsetof(type, member)); })#endif 在 container_of() 宏的定义中的 offsetof(type, member) 和 typeof() 初学者可能会对其很陌生,所以我们要先从理解 offsetof(type, member) 和 typeof() 的作用开始。
offsetof(type, member) 本质也是个宏定义,在 linux 源码的 toolsincludelinuxkernel.h 文件下定义如下:
#ifndef offsetof #define offsetof(type, member) ((size_t) &((type *)0)->member)#endif offsetof 宏中的 type 是指结构体的类型,member 是指结构体中的某个成员,作用是求出该成员的在该结构体中的偏移量。该宏首先将 0 (地址0)转化为 type * 的结构体指针,表示地址为 0 的结构体指针,然后通过取地址符 &((type *)0)->member) 取出该结构体指针中 member 成员的地址,最后再将地址值强转为 size_t 类型(内核中为 unsigned long 类型)即表示 member 成员在结构体中的偏移量。要理解该过程需要了解对结构体的内存分布,如图,结构体的内存分配是连续的,当结构体的地址为0时,成员的地址即为该成员的偏移量。
实例:
#include #ifndef offsetof#define offsetof(type, member) ((size_t) &((type *)0)->member)#endiftypedef struct _offset{ char member_0; int member_1; char member_2;}offset;int main(){ printf(%d, offsetof(offset, member_0)); printf(%d, offsetof(offset, member_1)); printf(%d, offsetof(offset, member_2)); return 0;} 输出:
offsetof实例结果输出 typeof() typeof() 是 gnu c 中的一个关键字,和 sizeof() 一样都是 c 语言中的关键字而不是函数。作用是返回传入数据的类型。实例:
#include int main(){ int a = 3; typeof(a) b = a; /* 求出a变量的类型,并创建一个b变量 */ printf(a=%d b=%d, a, b); return 0;} 输出:
img container_of(ptr, type, member) 了解了 offsetof() 宏和 typeof 关键字之后就比较好理解 container_of 宏的作用了。
const typeof(((type *)0)->member) * __mptr = (ptr) 该代码的作用实际上是将 0 转化为 type * 结构体类型,再取出结构体中的member成员 (type *)0)->member, 再通过 typeof 关键字获取 member 成员的类型,并定义一个 member 成员类型的指针 const typeof(((type *)0)->member) * __mptr,将传入的 ptr 指针赋值给 __mptr__mptr = (ptr)。
(type *)((char *)__mptr - offsetof(type, member)); 该代码是将获取的 member 成员地址强转为 char *(强转的目的是考虑指针的加减的实质是指针在内存的偏移,偏移量为指针类型所占字节的个数),减去 member 成员在 type 结构体中的偏移量,强转为 type * 后得到结构体的地址。实例:
#include #ifndef offsetof#define offsetof(type, member) ((size_t) &((type *)0)->member)#endif#ifndef container_of#define container_of(ptr, type, member) ({ const typeof(((type *)0)->member) * __mptr = (ptr); (type *)((char *)__mptr - offsetof(type, member)); })#endiftypedef struct _container { char member_0; int member_1; char member_2;}container;int main(void){ container *a = null; container b = {'a', 2, 'b'}; /* member_1在实例结构体中的地址 结构体类型 成员名 */ a = container_of(&b.member_1, container, member_1); printf(a->member_0 = %c, a->member_0); printf(a->member_1 = %d, a->member_1); printf(a->member_2 = %c, a->member_2); return 0;} 输出:
微雪电子(micro)USB转USART简介
【汽车大PK】林肯MKC/奥迪Q5
i.MX8MP开发板的功能测试
发电机强行励磁的作用_发电机强行励磁的注意事项
利用多通道ADC器件增强高端数据采集系统的应用性能
container_of()宏,太妙了~
汽车音响改装中布线的方法和布线原则
22个职场自学网站!用思维导图自律逆袭成大神!
叶绿素测定仪的特点有哪些
超高频电力测温安卓读写器的应用特点说明
斑马网络与山东高速合作,推出基于智联网汽车的“无感支付”功能
三星电子Fab 17工厂断电 DRAM和NAND芯片生产线受到波及
艾睿推CLLLC两级拓扑储能应用解决方案
DUV μLED在无线光通信领域的研究现状
奥林巴斯新款旗舰无反相机上手体验:三字总结快、贵、好!
联合国:机器人将导致发展中国家丧失三分之二就业岗位
通用前置放大器电路
为什么iphone x采用这个封装技术?
手机OLED屏幕更容易烧屏,平常使用时需注意
汽车安装车载摄像头有哪些好处