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

2017年(2)

2015年(11)

2014年(18)

2013年(8)

我的朋友

分类: LINUX

2014-01-25 00:46:01

1、好久没上CU了,今天来讲讲container_of这个宏解释以及应用,这个宏的作用是用来求结构题的入口地址。
开讲之前我们先来作一个定义,假设有如下结构体:
typedef struct tagSmall
{
    int iSmallId;
}SMALL_ST;
typedef struct tagBig
{
    int iBigId;
    SMALL_ST stTest;
}BIG_ST;
2、想看这个结构体在内核的定义:如下:
#define container_of(ptr, type, member) ({            \
    const typeof(((type *)0)->member) * __mptr = (ptr);    \
    (type *)((char *)__mptr - offsetof(type, member)); })
#endif
看需求:
假设我们现在知道了stTest的地址,那么我们要访问iBigId怎么办?显然我们就的知道BIG_ST的地址,而
container_of这个宏干的就是这个事。
先说一下解决这个问题的思路,其实很简单,你不是知道ptr的地址吗?结构体是一个连续的内存,那么我
只要求的你这个字段在结构体中的偏移量,两个一减不就是你外围结构体的地址了吗。
ptr就是你已知的成员地址,type就是你所在的结构体类型,member就是前面ptr的字段名。
接下来宏展开理解
1)、先看const typeof(((type *)0)->member) * __mptr = (ptr);怎么理解?
先看const char *__mptr = (ptr);这个很简单把,就是定义个变量初始化,再看前面的
其实一个意思,只不过这里要注意的是宏typeof();这个宏是用来取得变量类型的,比如你
传一个char型的变量i进去,它就返回char类型,在这里它的用处是什么,就是为了同意入口参数,
保证传进来的参数ptr的类型与字段member所对应的类型要一致。这种用法在很多地方都有用。
2)、(type *)((char *)__mptr - offsetof(type, member)); 又有一个新的宏offsetof,看这个命名就知道
是求便宜量的,在内核的定义如下:
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
关于&((TYPE *)0)->MEMBER)这个用的很巧妙,根据0这个特殊的指针来求偏移量,把0定义成TYPE类型的指针,
也就说这个指针一开始指向0地址,之后访问MEMBER成员,并取得地址,显然,这个地址就是MEMBER成员相对
0的偏移量,也就是相对于结构体的偏移量。
至此:container_of这个红的作用就说完了,感兴趣的可以自己写个代码测试去,我这里就不罗说了,这里
再讲以下这个宏在链表中的应用,在管理链表的时候,我们常常是把指针域和数据域分开成两个不同的结构体的,
然后我们自己在模块的中应用就直接定义一个结构体包含指针域和数据域,这个时候,我们可以通过操作链表域
进而管理数据域。个人觉得这个是很美妙的事,可以降低你代码的耦合度。
















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