typedef struct {
int a;
int b;
int member;
}type;
现在定义如下:
type test;
type *ptest;
并且已经 test.member的地址为ptr, 即,ptr = &test.member,但是并不知道test 的地址,求test的地址ptest。
显然ptest = ptr – member在成员中的偏移(上述例子中为8)。但是偏移要怎么求?具体要怎么写?
下面请看经典代码中的写法:
ptest = container_of(ptr, type, member);
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#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)的意义
((type *)0)为设计一个type类型的结构体,起始地址为0.
于是它的member就是((type *)0)->member;
member的地址 = 结构体((type *)0)的起始的地址 + member的偏移。
&((type *)0)->member = ((type *)0) + offset
于是,member在结构体中的偏移offset的计算方法如下:
offset = &((type *)0)->member - ((type *)0)
由于结构体起始地址为0,所以此结构体成员变量的偏移地址就等于其成员变量在结构体内的距离结构体开始部分的偏移量。
offset = &((type *)0)->member - ((type *)0) = &((type *)0)->member;
即:&((type *)0)->member就是取出其成员变量的偏移offset,#define offsetof将其转换为size_t类型。
再看container_of
const typeof( ((type *)0)->member ) *__mptr = (ptr);
typeof(((type *)0)->member)为取出member成员的变量类型。
再用其定义__mptr指针。ptr为指向该成员变量的指针。 __mptr为member数据类型的常量指针,其指向ptr所指向的变量处。
3,(type *)( (char *)__mptr - offsetof(type,member) )
(char*)__mptr转换为字节型指针。
根据上面的分析ptest = ptr – member在成员中的偏移
要求的地址,假设为X,就有X = (char*)__mptr - offsetof(type,member)), 但此是X还是char *, 需要强制类型转换。
(type *)X = (type*)(char*)__mptr - offsetof(type,member));
于是type *ptest = (type *)X = (type*)(char*)__mptr - offsetof(type,member));