c中出现的offsetof宏和container_of宏 解析
1、offsetof宏用于求成员变量在结构体中的偏移量
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
我们来逐步分解这个宏:
((TYPE*)0) 把地址值为0指针转换为TYPE指针
((TYPE*)0)->MEMBER 解指针应用,求起始地址为0的类型为TYPE的成员MEMBER
&((TYPE*)0)->MEMBER 求起始地址为0的类型为TYPE的成员MEMBER的地址
((size_t)&((TYPE*)0)->MEMBER) 把起始地址为0的类型为TYPE的成员MEMBER的地址值类型转换为size_t类型
综上我们可以看到一个很巧妙的地方,就是把值为0的地址转换为TYPE*指针,这样求得的MEMBER的地址就是成员MEMBER在TYPE中的偏移量。
2、container_of宏用于已知一个结构体变量中某一成员变量的地址,反过来求结构体变量的起始地址
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr – offsetof(type,member) );})
这个宏展开是一个二分拣表达式,它的值是最后一个分句决定的,也就是说这个宏展开后返回的值类型是type *
我们也逐步来分解这个宏:
const typeof( ((type *)0)->member ) *__mptr = (ptr); 声明一个const的结构体中成员member类型的指针变量__mptr,并使用ptr赋值。
(type *)( (char *)__mptr – offsetof(type,member) ); 把指针__mptr的类型转换为char *,并减去member在type中的偏移量,最后再把这个求得的指针值转换为type *,而这个值就是成员变量(*ptr)对应的结构体type变量的起始地址了。
3、Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <stdio.h> #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) );}) struct Test { int a; short b; char c; }; int main() { Test t; printf("offsetof(Test, a)=%d\n", offsetof(Test, a)); printf("offsetof(Test, b)=%d\n", offsetof(Test, b)); printf("offsetof(Test, c)=%d\n", offsetof(Test, c)); printf("address t=%p, container_of t=%p\n", &t, container_of(&t.a, Test, a)); printf("address t=%p, container_of t=%p\n", &t, container_of(&t.b, Test, b)); printf("address t=%p, container_of t=%p\n", &t, container_of(&t.c, Test, c)); return 0; } |
近期评论