码迷,mamicode.com
首页 > 其他好文 > 详细

由结构体成员地址计算结构体地址——list_entry()原理详解

时间:2015-07-15 16:30:48      阅读:138      评论:0      收藏:0      [点我收藏+]

标签:

  1. #define list_entry(ptr, type, member) container_of(ptr, type, member)
在进行编程的时候,我们经常在知道结构体地址的情况下,寻找其中某个成员的地址;但是知道了成员的地址,如果找到这个结构体对应的地址呢?
Linux内核中,获取节点地址的函数是list_entry(),它的宏定义如上所示。
我们再来查找container_of(ptr, type, member)的定义,发现它依然是一个宏定义:
  1. #define container_of(ptr, type, member) \
  2. ({ \
  3. const typeof(((type *)0)->member) * __mptr = (ptr); \
  4. (type *)((char *)__mptr - offsetof(type, member)); \
  5. })
container_of(ptr, type, member)的宏定义中,真正返回节点地址的是最后一句话,
而在最后一句话中offsetof(TYPE, MEMBER)依然是一个宏定义。
  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  1. typedef __kernel_size_t size_t;
  2. typedef unsigned int __kernel_size_t;
通过逐层查找之后我们来说一下list_entry()函数的具体实现,我们从下往上说起。


    1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  • TYPE
这是我们自定义的结构体类型,它的内部至少一个list_head型成员变量,如下:
  1. struct TYPR
  2. {
  3. //...
  4. struct list_head member;
  5. //...
  6. };
其中list_head也是一个结构体,它的定义我们稍后再说。
  • MEMBER
这是TYPE对象中list_head型变量的变量名。
  • 语句解析
(TYPE *)0:将0强制转换成TYPE型指针,则该指针一定指向0地址(数据段基址)。
&((TYPE *)0)->MEMBER这句话其实是&(((TYPE *)0)->MEMBER),通过该指针访问TYPE的MEMBER成员并得到其地址。
由于该指针的起始地址是0,那么&((TYPE *)0)->MEMBER也就是一个TYPE型变量的起始地址
与该变量内部MEMBER成员变量起始地址之间的偏移量,这个偏移量对于所有的TYPE型变量都是成立的。
那么,接下来的思路便很明确了,我们只要知道一个TYPE类型变量中MEMBER变量的起始地址,减去
offsetof(TYPE, MEMBER)这个偏移量,就可以得到TYPE类型变量的起始地址。
它的的对应关系如下图所示:
技术分享

思路很清晰,但还有一些细节需要注意,我们继续看代码。

2.
  1. #define container_of(ptr, type, member) \
  2. ({ \
  3. const typeof(((type *)0)->member) * __mptr = (ptr); \
  4. (type *)((char *)__mptr - offsetof(type, member)); \
  5. })
  • const typeof(((type *)0)->member) * __mptr = (ptr);
由于下面我们要对指针进行强制类型转换,所以这里我们又申请一个指针,指向和ptr相同的位置。
这里的ptr指的是实际list_head member的地址。
  • (char *)__mptr
由于offsetof()函数求得的是偏移字节数,所以这里(char *)__mptr使得指针的加减操作步长为1Byte
然后二者相减便可以得到TYPE变量的起始地址,最后通过(type *)类型转换,将该地址转换为TYPE类型的指针。
再向上就是一些宏定义没有什么可说的了。








































由结构体成员地址计算结构体地址——list_entry()原理详解

标签:

原文地址:http://www.cnblogs.com/fengkang1008/p/4648484.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!