Chinaunix首页 | 论坛 | 博客
  • 博客访问: 175775
  • 博文数量: 27
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 618
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-15 09:12
文章分类
文章存档

2014年(17)

2013年(10)

我的朋友

分类: LINUX

2013-11-28 14:25:36

container_of的函数实现:
  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
  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)); })  

关于offsetof见stddef.h中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
TYPE是某struct的类型 0是一个假想TYPE类型struct,MEMBER是该struct中的一个成员. 由于该struct的基地址为0, MEMBER的地址就是该成员相对与struct头地址的偏移量.
关于typeof,这是gcc的C语言扩展保留字,用于声明变量类型.
const typeof( ((type *)0->member ) *__mptr = (ptr);意思是声明一个与member同一个类型的指针常量 *__mptr,并初始化为ptr.
(type *)( (char *)__mptr - offsetof(type,member) );意思是__mptr的地址减去member在该struct中的偏移量得到的地址, 再转换成type型指针. 该指针就是member的入口地址了.

如下图所示:

定义一个结构体struct student结构体,初始化一个stu,container_of的作用是,知道stu中一个成员的地址,算出stu这个结构体的地址。如知道stu->sex的地址,返回stu的地址

分三步完成:

(1)得到结构体成员  物理地址   如得到:sut->sex

const typeof(((type *)0)->member)*__mptr = (ptr);

(2)得到成员在结构体中的偏移量 ,如上图得到  在sturct student中,成员sex的  偏移量为 20

offsetof(type,member)

(3)得到stu的  物理地址  ,如上图得到  sut = stu->sex - 20  ,这样就完成了返回stu物理地址。 

(type *)( (char *)__mptr - offsetof(type,member) )

下面看一个实例程序:

  1. #include  
  2. struct student{  
  3.         char name[20];  
  4.         char sex;  
  5.         int num;  
  6. }stu= {"mingming",'m',101};  
  7. main()  
  8. {  
  9.         struct student *stu_ptr;  
  10.         int offset;  
  11.         const typeof(((struct student*)0)->sex) *_mptr = &stu.sex;//(1)得到成员_mptr= stu->sex的物理地址  
  12.                 printf("_mptr= 0x%d\n",_mptr);  
  13.         
  14.   offset = (int)(&((struct student *)0)->sex);//(2)成员在结构体中绝对偏移量  
  15.                 printf("offset = %d\n",offset);  
  16.   
  17.         stu_ptr = (struct student *)((char*)_mptr - offset);//(3)得到结构体stu 的物理地址  
  18.             printf("stu_ptr = 0x%d\n",stu_ptr);  
  19.         
  20.   printf("stu_ptr->name:%s\tstu_ptr->sex:%c\n", stu_ptr->name, stu_ptr->sex);  
  21.         return 0;  
  22. }        
container_of可以分解为上面程序中的三步完成:

(1)得到成员_mptr= stu->sex的物理地址

首先定义一个 _mptr指针, 类型为struct student结构体中sex成员的类型,typeof 为获取(((struct student*)0)->sex)的类型,此处此类型为char,((struct student*)0)在offsetof处讲解

(2)成员在结构体中绝对偏移量

((struct student*)0)为 把 0地址 强制转化为指向student结构体类型的指针,该指针从地址 0 开始的 21个字节用来存放name 与 sex(char name〔20〕与 char sex共21字节),sex存放在第20个字节出(从0字节开始),&((struct student *)0)->sex 取出sex地址(此处即为20) 并强制转化为整形,所以offset为20,后面的printf结果将证明这一点

(3)得到结构体stu 的物理地址

((char*)_mptr - offset)此处先把_mptr指针转化为字符形指针,(为什么这么做呢? 如果_mptr为整形指针 _mptr - offset 相当于减去 sizeof(int)*offset个字节),减去 offset值 相当于 得到_mptr所在结构体的首地址(即stu的地址),然后我们把 该地址 强制转化为 struct student类型即可正常使用了

上面程序运行结果为:

  1. root@android-virtual-machine:/uniteq_smb/test# ./teset_conta   
  2. _mptr= 0x134520872  
  3. offset = 20  
  4. stu_ptr = 0x134520852  
  5. stu_ptr->name:mingming   stu_ptr->sex:m 
阅读(1424) | 评论(0) | 转发(1) |
0

上一篇:Workqueue机制

下一篇:list_for_each_entry

给主人留下些什么吧!~~