container_of宏定义在linux内核的kernel.h头文件中有声明,他的目的是想计算出某个变量被包含在某个结构体中,这个结构体变量的地址。
container_of定义如下:
*/ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
- 第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
- 第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。
这里有一个难点就是如何可以找到成员member在这个结构体中的偏移量。
/* linux-2.6.38.8/include/linux/compiler-gcc4.h */ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) /* linux-2.6.38.8/include/linux/stddef.h */ #undef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #include <stdio.h> struct test_struct { int num; char ch; float fl; }; int main(void) { printf("offsetof(struct test_struct, num) = %d\n", offsetof(struct test_struct, num)); printf("offsetof(struct test_struct, ch) = %d\n", offsetof(struct test_struct, ch)); printf("offsetof(struct test_struct, fl) = %d\n", offsetof(struct test_struct, fl)); return 0; }
例子输出结果:
offsetof(struct test_struct, num) = 0 offsetof(struct test_struct, ch) = 4 offsetof(struct test_struct, fl) = 8
其中代码难以理解的地方就是它灵活地运用了0地址。如果觉得&( (struct test_struct *)0 )->ch这样的代码不好理解,那么我们可以假设在0地址分配了一个结构体变量struct test_struct a,然后定义结构体指针变量p并指向a(struct test_struct *p = &a),如此我们就可以通过&p->ch获得成员ch的地址。由于a的首地址为0x0,所以成员ch的首地址为0x4。
最后通过强制类型转换(size_t)把一个地址值转换为一个整数。
分析完container_of的定义,接下来举两个例子来体会一下它的使用方法。
正确的例子,如清单2:
/* linux-2.6.38.8/include/linux/compiler-gcc4.h */ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) /* linux-2.6.38.8/include/linux/stddef.h */ #undef offsetof #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif /* linux-2.6.38.8/include/linux/kernel.h * * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #include <stdio.h> struct test_struct { int num; char ch; float fl; }; int main(void) { struct test_struct init_test_struct = { 99, 'C', 59.12 }; char *char_ptr = &init_test_struct.ch; struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch); printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n", test_struct->num, test_struct->ch, test_struct->fl); return 0; }
例子输出结果:
test_struct->num = 99 test_struct->ch = C test_struct->fl = 59.119999