container_of宏在很久以前的文章我就已经有分析写过了,但是看回去,感觉以前自己对这个宏的表达描述分析能力还是有待提高,毕竟那时候刚接触linux内核不久,整个人都懵懵哒,无法说得让别人通俗易懂。
那么这个宏整体是什么样子的呢?
//获取结构体成员相对于结构体的偏移
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)
//通过获取结构体中的某个成员,反推该结构体的指针
#define container_of(ptr, type , member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr) ; \
(type *)((char *)__mptr - offsetof(type,member)) ;})
作用:通过某个结构体中的某个成员变量的指针,反推这个结构体变量的指针。说白了,我定义一个结构体变量和结构体指针,变量.结构体中某一个成员(这个我是知道的),还有知道它的地址,也就是&(变量.结构体中某一个成员),通过这两个参数,还有结构体的type,返回得到的就是结构体的首地址。
工作原理:先用typeof获取变量的数据类型,也就是member成员的类型,然后将member这个成员 的指针转成自己类型的指针,再从offsetof相减,就得到整个结构体变量的首地址了,再将该地址强制转化为type *。
关于offsetof的作用就不再阐述,文章超链接在这:Offsetof宏的作用和原理
接下来看看如何使用吧,也很简单。
#include <stdio.h>
#include <stdlib.h>
//获取结构体成员相对于结构体的偏移
#define offsetof(TYPE,MEMBER) ((int) &((TYPE *)0)->MEMBER)
//通过获取结构体中的某个成员的,反推该结构体的指针
#define container_of(ptr, type , member) ({ \
const typeof(((type *)0)->member) *__mptr = (ptr) ; \
(type *)((char *)__mptr - offsetof(type,member)) ;})
#pragma pack(4)
struct ptr
{
char a ;
short b ;
int c ;
double d ;
};
#pragma pack()
int main(void)
{
struct ptr Pt ;
struct ptr *pt ;
printf("ptr:%d\n",sizeof(struct ptr));//16
//获取结构体的首地址
printf("ptr:%p\n",&Pt); //0028FEA8
Pt.a = 'a';
Pt.b = 2 ;
Pt.c = 4 ;
Pt.d = 12.04 ;
//通过container_of获取结构体的首地址
pt = container_of(&Pt.c, struct ptr , c);
printf("pt:%p\n",pt); //0028FEA8
printf("a:%c\n",pt->a) ; //'a'
printf("b:%d\n",pt->b) ; //2
printf("c:%d\n",pt->c) ; //4
printf("d:%.2lf\n",pt->d);//12.04
return 0 ;
}