container_of
1 /** 2 * container_of - cast a member of a structure out to the containing structure 3 * @ptr: the pointer to the member. 4 * @type: the type of the container struct this is embedded in. 5 * @member: the name of the member within the struct. 6 * 7 */ 8 #define container_of(ptr, type, member) ({ \ 9 const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 10 (type *)( (char *)__mptr - offsetof(type,member) );})
它的作用显而易见,那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。
1 #undef offsetof 2 #ifdef __compiler_offsetof 3 #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) 4 #else 5 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 6 #endif
需要注意的是,要使用container_of,则type中成员member不能为指针。(若其为指针,则ptr为指针的指针,为程序带来复杂性)。
此处错误应删除(指针成员与非指针成员同等处理即可)。例程中如下代码即可验证,但是若为指针时container_of()的第一参数ptr存储的是member成员的地址(即指针的地址),而非指针值。
#if 1 stu2.scc="ABCD"; str = &(stu2.scc); pstu1 = container_of(str, stu, scc); printf("The score is %s\n", pstu1->scc); #endif
详细示例参考“设备结构体设计思考”。
#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) );}) typedef struct { char score; } core_grade; typedef struct { int no; int age; core_grade grade; char sc;
char *scc; } stu, *pstu; int main(int argc, char *argv[]) { stu stu1, stu2, *pstu1=NULL; char *pch = NULL;
void *str = NULL; // save addr #if 0 stu1.grade.score='A'; pch = &(stu1.grade.score); pstu1 = container_of(pch, stu, score); printf("The score is %c\n", (pstu1->grade).score); #endif #if 1 stu1.sc='A'; pch = &(stu1.sc); pstu1 = container_of(pch, stu, sc); printf("The score is %c\n", pstu1->sc); #endif
#if 1
stu2.scc="ABCD";
str = &(stu2.scc);
pstu1 = container_of(str, stu, scc);
printf("The score is %s\n", pstu1->scc);
#endif
return 0; }
上述代码同时验证了,container_of不能穿透结构体(#if 0...#endif)。
上述结论错误,container_of()的第二个参数type和第三个参数member必须是直接的包含关系时才可以;若是间接包含,则第三个参数必须拓展到直接包含的成员引用才可以。
上述code中container_of报错:
pstu1 = container_of(pch, stu, score);
structinc.c:6:30: error: ‘stu {aka struct <anonymous>}’ has no member named ‘score’ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
但改为如下code则编译成功:
pstu1 = container_of(pch, stu, grade.score);