Chinaunix首页 | 论坛 | 博客
  • 博客访问: 101392
  • 博文数量: 21
  • 博客积分: 193
  • 博客等级: 入伍新兵
  • 技术积分: 155
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-30 10:36
文章分类
文章存档

2011年(21)

分类:

2011-11-11 13:16:37

看内核源码时,看到一个 宏定义,蛮有意思,ptr是成员变量的指针,type是指结构体的类型,member是成员变量的名字,container_of作用是在已知某一个成员变量的名字,指针和结构体类型的情况下,计算结构体的起始地址。用该成员变量的指针,减去它相对于结构体起始位置的偏移量。

typeof(((type*)0)->member)  获取member的类型。 定义一个临时指针指向ptr , 把__mptr 转换成char*类型,因为offsetof得到的偏移量是以字节为单位,两者相减得到结构体的起始位置,再强制转换为type类型。


  1. /**
  2.  * container_of - cast a member of a structure out to the containing structure
  3.  *
  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) );})

  12. 包含在/include/Linux/kernel.h
这里面还有两个需要说明的地方,一个是typeof 另外一个是offsetof。

typedof 是个GCC的关键字,是GCC特性。可以通过一个变量的名字获得其类型,这是编译器能做到的。

offsetof 是一个宏定义,是C99 的一个标准,可以通过 man offsetof查看该宏。可以直接用


  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
TYPE 表示一个结构体类型,MEMBER是结构体中的一个成员变量的名字,offsetof的作用是计算成员变量MEMBER相对于结构体起始位置的内存偏移量,以字节为单位。 先把0强制转化为TYPE类型的指针,然后找到成员变量MEMBER,用取地址符得到MEMBER的地址。因为结构体是从地址0开始,所以MEMBER的地址就是相对于结构体开始位置的偏移量。

  1. #include<stdio.h>
  2. #include<stddef.h>

  3. #define offset(type,member) ((size_t)&((type*)0)->member)

  4. struct st
  5. {
  6.     int a;
  7.     char b;
  8.     char c;
  9.     int d
  10. };

  11. struct sd
  12. {
  13.     int a;
  14.     struct st b;
  15.     char c;
  16. };

  17. int main()
  18. {
  19.     printf("%d\n",offset(struct st,c));
  20.     printf("%d\n",offset(struct st,d));
  21.     printf("%d\n",offset(struct sd,b));
  22.     printf("%d\n\n",offset(struct sd,c));

  23.     printf("%d\n",offsetof(struct st,c));
  24.     printf("%d\n",offsetof(struct sd,b));
  25.     printf("%d\n",offsetof(struct sd,c));
  1.     struct sd test;
  2.     int *p=&test.c;
  3.     struct st *tp=&test.b;

  4.     struct sd *dp=container_of(p,struct sd,c);
  5.     struct st *dq=container_of(tp,struct st,b);
  6.     // 已知member c的地址,求的test首地址
  7.     printf("%X\n",&test);
  8.     printf("%X\n",dp); // 已知 test中 b c 的地址, 求得 test 的地址。
  9.     printf("%X\n",dq);
  1.     return 0;

  2. }
  1. 5 //c
  2. 8 //d 编译器使d按照4字节倍数对齐了
  3. 4
  4. 16

  5. 5
  6. 4
  7. 16 //c相对于起始 偏移 sizeof(int)+ sizeof(struct st)=4+12=16





阅读(2367) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~