container_of函数原型
- container_of(ptr,type,member) 该函数原理:已知结构体type的成员member的地址ptr,求结构体type的首地址。
1 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 2 3 #define container_of(ptr, type, member) ({ \ 4 const typeof( ((type *) 0)->member)* __mptr = (ptr); \ 5 (type *)((char *)__mptr - offsetof(type, member)); })
函数实现由两部分:① 判断ptr 与 member的类型是否一致;② 计算起始地址。
- container_of函数实现中第一行解释:(这行代码很巧妙)
根据查找资料比较认可的说法:(1)检查三个参数,如果member是type的成员,但是ptr所指的类型不是member(也就是ptr是正确的,但是该ptr指向的不是member成员)那么计算出来的地址就是错误的;这种情况编译器不会报错和警告;(2)若开发者想赋值保存ptr,会在右边加上类型强转以免发生参数传输类型不符的情况。const typeof( ((type *) 0)->member)* __mptr = typeof( ( ((type *)0) -> member) *) (ptr); 内核禁止不规范的操作。详见关于container_of 第一行的__mptr作用的总结 - 内核源码-Chinaunix;
- 实现第二行的解释
& ( ((type *) 0)->member )的作用是求出结构体起始地址到成员member的字节数大小,返回类型是size_t 无符号整型(否则内核会发出警告);这儿的0可以理解为被强制转换为 (type *)类型,它的作用就是指向该结构体起始地址的指针 ,从而求出相对地址的大小。接着利用(char *)__mptr :转化为char *是因为字节数减一就是减一(若为int型,则减一意味着字节数减四);再减去偏移地址,就是结构体的起始地址。