1、container_of :
(container_of宏定义在[include/linux/kernel.h]中, offsetof见stddef.h中)
作用:
根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针
定义:
-
#define container_of(ptr, type, member) ({ \
-
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-
(type *)( (char *)__mptr - offsetof(type,member) );})
-
#endif
理解:const typeof( ((type *)0->member ) *__mptr = (ptr) :
((type *)0->member):把0地址强制转换成指向type类型结构的指针,menber为type类型结构体的成员
typeof:获取结构类型; exp: int a; typeof(a) b;(则typeof(a) b;等效 int b);
所以typeof( ((type *)0->member )的意思是获取type结构体成员menber的结构类型,如果menber是char类型,则起等效为char,const typeof( ((type *)0->member ) *__mptr = (ptr)则等效char *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) ) :
意思是__mptr的地址减去member在该struct中的偏移量得到的地址, 再转换成type型指针. 该指针就是member的入口地址了;
例子:
-
#include<stdio.h>
-
struct student{
-
char name[20];
-
char sex;
-
}stu={"zhangsan",'m'};
-
-
main()
-
{
-
struct student *stu_ptr; //存储container_of宏的返回值
-
int offset; //存储offsetof宏的返回值
-
//下面三行代码等同于 container_of(&stu.sex,struct student, sex )参数带入的情形
-
const typeof(((struct student*)0)->sex) *_mptr = &stu.sex;
-
//首先定义一个 _mptr指针, 类型为struct student结构体中sex成员的类型
-
//typeof 为获取(((struct student*)0)->sex)的类型,此处此类型为char
-
//((struct student*)0)在offsetof处讲解
-
offset = (int)(&((struct student *)0)->sex);
-
/*((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结果将证明这一点*/
-
-
stu_ptr = (struct student *)((char*)_mptr - offset);
-
/*((char*)_mptr - offset)此处先把_mptr指针转化为字符形指针
-
(为什么这么做呢? 如果_mptr为整形指针 _mptr - offset 相当于减去 sizeof(int)*offset个字节)
-
减去 offset值 相当于 得到_mptr所在结构体的首地址(即stu的地址)
-
然后我们把 该地址 强制转化为 struct student类型即可正常使用了*/
-
-
printf("offsetof stu.sex = %d/n",offset);
-
printf("stu_ptr->name:%s/tstu_ptr->sex:%c/n", stu_ptr->name, stu_ptr->sex);
-
return 0;
-
}
-
-
例二:
-
-
它的作用显而易见,那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。比如,有一个结构体变量,其定义如下:
-
-
1. struct demo_struct {
-
2. type1 member1;
-
3. type2 member2;
-
4. type3 member3;
-
5. type4 member4;
-
6. };
-
7.
-
8. struct demo_struct demo;
-
-
同时,在另一个地方,获得了变量demo中的某一个域成员变量的指针,比如:
-
-
1. type3 *memp = get_member_pointer_from_somewhere();
-
-
此时,如果需要获取指向整个结构体变量的指针,而不仅仅只是其某一个域成员变量的指针,我们就可以这么做:
-
-
1. struct demo_struct *demop = container_of(memp, struct demo_struct, member3);
-
首先,我们将container_of(memp, struct demo_struct, type3)根据宏的定义进行展开如下:
-
-
1. struct demo_struct *demop = ({ /
-
2. const typeof( ((struct demo_struct *)0)->member3 ) *__mptr = (memp); /
-
3. (struct demo_struct *)( (char *)__mptr - offsetof(struct demo_struct, member3) );})
-
-
其中,typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型。因此,上述代码中的第2行的作用是首先使用typeof获取结构体域变量member3的类型为 type3,然后定义了一个type3指针类型的临时变量__mptr,并将实际结构体变量中的域变量的指针memp的值赋给临时变量__mptr。
-
-
假设结构体变量demo在实际内存中的位置如下图所示:
-
demo
-
+-------------+ 0xA000
-
| member1 |
-
+-------------+ 0xA004
-
| member2 |
-
| |
-
+-------------+ 0xA010
-
| member3 |
-
| |
-
+-------------+ 0xA018
-
| member4 |
-
+-------------+
-
-
则,在执行了上述代码的第2行之后__mptr的值即为0xA010。
-
-
再看上述代码的第3行,其中需要说明的是offsetof,它定义在include/linux/stddef.h中,其定义如下:
-
-
1. 24#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-
同样,我们将上述的offsetof调用展开,即为:
-
-
1. (struct demo_struct *)( (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) );
-
-
可见,offsetof的实现原理就是取结构体中的域成员相对于地址0的偏移地址,也就是域成员变量相对于结构体变量首地址的偏移。
-
-
因此,offsetof(struct demo_struct, member3)调用返回的值就是member3相对于demo变量的偏移。结合上述给出的变量地址分布图可知,offsetof(struct demo_struct, member3)将返回0x10。
-
-
于是,由上述分析可知,此时,__mptr==0xA010,offsetof(struct demo_struct, member3)==0x10。
-
因此, (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) == 0xA010 - 0x10 == 0xA000,也就是结构体变量demo的首地址(如上图所示)。
-
-
由此,container_of实现了根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针的功能。
2、__attribute__((unused))
表示该函数或变量可能不使用,这个属性可以避免编译器产生警告信息。
阅读(698) | 评论(0) | 转发(0) |