在驱动过程中,一直有一个做法,就是通过,我知道的一个结构体的一个成员,那么我就可以拿到整个结构体的数据
我们也称为以小博大。
就比如字符设备驱动过程中的input_dev input_handler 和evdev_handl 这三个结构体就天天在那博来博去的。
乍一想:就是通过,我知道的一个结构体的一个成员,那么我就可以拿到整个结构体的数据。
这肯定没问题啊,我都知道一个成员了,那拿到整个结构体的数据这不是易如反掌吗?
但是真的让你去操作你会怎么操作
?
?
?
内核是定义一个宏去完成以小博大
container_of:
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );
})
它这里面还定义了俩个宏支持这个宏
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
还有一个typeof的宏
typeof:这个宏就是可以获取到一个变量的类型,如我们可以这样写代码:{int a; typeof(a) b;}这段代码等价于:{int a; int b;}
接下来看一个很有意识的宏
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
首先定义了一个宏叫 offsetof
它可以传递参数(TYPE, MEMBER) 一个是结构体类型 一个是已经知道的成员
它用来替换掉了:
((size_t) &((TYPE *)0)->MEMBER)
慢慢分析
(TYPE *)0 :这个的意识就是 我把0强制转化成type的地址 那么这个就是一个type的0地址。
((TYPE *)0)->MEMBER) :这个就是我在0地址创建了一个type类型的结构体 ,我们还知道它有一个成员MEMBER;
&((TYPE *)0)->MEMBER) :这样我就拿到了以0为起始地址的type类型的结构体,的已知成员的的地址。
((size_t) &((TYPE *)0)->MEMBER) :把它强转成((size_t)型,就是偏移量了。
所以说,这个宏求出了这个成员在结构体中的偏移量,
那 我成员地址有了,偏移量有了,不就可以找到结构体首地址了吗?