在linux内核中经常遇到container_of宏,定义如下:
#define container_of(ptr, type, member) ({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})
其中用到的宏offsetof定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
container_of(ptr, type, member) 是假设我们知道了一个type类型的结构体,拥有member对象,我们需要根据指向member对象的指针ptr定位到指向type类型的指针。
比如:
struct type{
int a;
double member;
};
struct ptr tmp;
double * ptr = &tmp.b;
那么我们现在就是根据指针ptr,类型type,成员member,找到指向type本身的指针。
该宏的含义如下:
假设我们定义一个类型为type的变量,如果其地址为0,那么成员member的地址就是成员member在type中的偏移。那么成员member的实际位置减去在结构体中的偏移就是该结构体的地址。主要的步骤是第二步:(type *)( (char *)__mptr - offsetof(type,member) ; 这里的__mptr 是同等于传递进来的ptr的。
由于这是宏,为了避免使用宏,扩展之后的问题,没有直接使用传递进来的指针直接进行加减。而是定义了一个变量指向它。由于我们不知道成员member的类型,所以第一步使用了一个typeof来获得类型,然后定义这样的一个变量指向传递来的指针。 const typeof( ((type *)0)->member ) *__mptr = (ptr);
这里比较有技巧的就是((type *)0)->member;
还有一个要注意的地方,就是第二步算减法的时候,定义要讲第一个指针强制类型转换为char *,这样指针之间的相减才是以char为单位的,而不是以member类型为单位。