最近学习为Android添加编写内核驱动,遇到的第一个问题就是linux中大名鼎鼎的container_of()宏。
container_of()是Linux内核中一个非常重要的宏,主要功能就是:根据结构体中一个域成员的地址获取整个结构体的地址。
container_of()定义如下:
1 /** 2 * container_of - cast a member of a structure out to the containing structure 3 * @ptr: the pointer to the member. 4 * @type: the type of the container struct this is embedded in. 5 * @member: the name of the member within the struct. 6 * 7 */ 8 #define container_of(ptr, type, member) ({ 9 const typeof( ((type *)0)->member ) *__mptr = (ptr); 10 (type *)( (char *)__mptr - offsetof(type,member) );})
路径:(Android源码)//kernel/goldfish/include/linux/kernel.h(学习android,就使用Android中的kernel代码了)。
该宏的执行主要分为两步:
第一步、定义一个变量保存传入的域成员的地址。
const typeof( ((type *)0)->member ) *__mptr = (ptr);
以0为内存地址并强转为type类型(传入的结构体),通过->member(传入的域成员)获取到结构体的域成员,并用typeof()取得域成员的类型,以域成员的类型定义一个临时变量__mptr,把域成员的地址ptr保存到__mptr中。
第二步、使用域成员地址减去域成员相对于结构体首地址的偏移。
这一步首先使用offsetof()取得域成员相对于结构体首地址的偏移,再使用域成员的实际地址__mptr减去该偏移就可以得到结构体的首地址。
下面以一张图来形象的描述该过程:
当前传入域成员k的地址0x0010008,需要获取整个结构体的地址。首先使用offsetof()获取k相对于结构体地址的偏移8,再用0x0010008-8=0x00010000,这就是结构体的地址。
理解清楚了就会发现是很简单的一件事。
参考:
http://www.cnblogs.com/sdphome/archive/2011/09/14/2176624.html
http://www.cnblogs.com/hicjiajia/archive/2012/07/01/2571791.html
http://blog.csdn.net/npy_lp/article/details/7010752