Chinaunix首页 | 论坛 | 博客
  • 博客访问: 412051
  • 博文数量: 36
  • 博客积分: 960
  • 博客等级: 准尉
  • 技术积分: 1368
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-13 19:26
文章分类
文章存档

2018年(3)

2012年(6)

2011年(27)

分类: LINUX

2011-11-25 18:44:24

-------------------------------------------
本文系作者原创, 欢迎大家转载!
转载请注明出处:netwalker.blog.chinaunix.net
-------------------------------------------

由于内核中定义了很多复杂的数据结构,而它们的实例中的成员在作为函数参数传递的时,函数中可能需要对它的包含者中的其他的兄弟成员进行处理,这就需要只根据成员地址就可以获取整个结构体变量的地址的操作。container_of提供了这样的操作:

  1. include/linux/kernel.h
  2. /**
  3.  * container_of - cast a member of a structure out to the containing structure
  4.  * @ptr: the pointer to the member.
  5.  * @type: the type of the container struct this is embedded in.
  6.  * @member: the name of the member within the struct.
  7.  *
  8.  */
  9. #define container_of(ptr, type, member) ({ \
  10.         const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  11.         (type *)( (char *)__mptr - offsetof(type,member) );})

巧妇难为无米之炊,无论如何,都需要告知container_of该整体结构体变量的类型以及当前成员的指针和成员名。typeof用来获取成员的类型并定义一个临时变量__mptr来存储当前成员的地址。offsetof用来获取当前成员相对于整体结构体地址的偏移。它定义为:

  1. include/linux/compiler-gcc4.h
  2. #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)

  3. include/linux/stddef.h
  4. #ifdef __compiler_offsetof
  5. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
  6. #else
  7. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  8. #endif

如果定义了__compiler_offsetof,则使用Gcc编译器内建的offsetof宏,它的作用和此处定义的offsetof相同。它将0地址作为当前结构的首地址,从而直接通过指针访问成员得到的地址即为偏移。将实际使用的结构体中的成员指针__mptr减去offsetof,就得到了结构体的地址。

  1. #include <stdio.h>
  2. ......
  3. typedef struct man
  4. {
  5.     char name[32];
  6.     unsigned int id;    
  7.     unsigned char age;
  8.     char address[64];
  9. }man_t;

  10. int main()
  11. {
  12.     man_t tom = {"Tom", 0, 24, "ShangHai China"};
  13.     man_t *man = NULL;
  14.     
  15.     printf("tom:%p, tom.age:%p, offsetof(man_t, age): %d\n",
  16.                     &tom, &tom.age, offsetof(man_t, age));
  17.                     
  18.     man = container_of(&tom.age, man_t, age);
  19.     printf("tom.name:%s, tom.id:%d, tom.age:%u, tom.address:%s\n",
  20.                     man->name, man->id, man->age, man->address);
  21.     
  22.     return 0;
  23. }

测试结果如下:

  1. tom:0xbf85cda4, tom.age:0xbf85cdc8, offsetof(man_t, age): 36
  2. tom.name:Tom, tom.id:0, tom.age:24, tom.address:ShangHai China
阅读(2956) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~