Chinaunix首页 | 论坛 | 博客
  • 博客访问: 152328
  • 博文数量: 53
  • 博客积分: 2059
  • 博客等级: 大尉
  • 技术积分: 490
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-14 20:25
文章分类
文章存档

2012年(1)

2011年(25)

2010年(16)

2009年(11)

我的朋友

分类: LINUX

2011-11-06 09:51:15

今天看内核代码,发现container_of的用法,上网查下它的用法,原来是 在已知结构体的某个成员的指针时,求出整个结构体的首指针地址,具体宏展开如下:

  1. #define container_of(ptr, type, member) ({ \

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

  3. (type *)( (char *)__mptr - offsetof(type,member) );})

具体解释如下:
typeof是gcc的一个扩展,用于确定一个变量的类型,有点像C++的RTTI,常用于表达式内的语句,在定义宏时,如果需要临时变量,可以这样做:

  1. #define max(a,b) \
  2. ({ typeof (a) _a = (a); \
  3. typeof (b) _b = (b); \
  4. _a > _b ? _a : _b; })

它可以保证我们定义的变量_a/_b与宏传入的变量a/b类型匹配,而不会产生编译器告警。

因此container_of的第一行就是定义一个与member类型匹配的变量__mptr,赋值后,__mptr为宏参数中的待转换指针,因为只是类型转换,不涉及数据读写,((type*)0)是没有任何副作用的。

第二行用__mptr减去member变量在type中的偏移,这样便可实际访问到ptr相同偏移,也即type的实际首地址了。offsetof有两种定义:

 

  1. #ifdef __compiler_offsetof
  2. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
  3. #else
  4. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  5. #endif

 

__compiler_offsetof即__builtin_offsetof,__builtin_offsetof可能是gcc內建的支持(见gcc源码c-parser.c),
从后一种实现方式可以明显看到这一技巧,假定一个从0地址开始的结构体,取其成员member的地址正是结构体内的偏移。

linux下的c语言的宏果然是博大精深呀,还得学习,下次会介绍下有关模块注册中宏的用法的~

 

http://yaronspace.cn/blog/archives/1026

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