当前位置:   article > 正文

container_of 宏_containerof宏

containerof宏

宏的作用:通过结构体中的元素地址计算结构体的地址。

宏定义:

#define container_of(ptr, type, member) ({             /
         const typeof( ((type *)0)->member ) *__mptr = (ptr);     /
         (type *)( (char *)__mptr - offsetof(type,member) );})
  • 1
  • 2
  • 3

分析:

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

其中:
typeof:这是gcc的C语言扩展保留字, 用于从变量获取类型
ptr:指向结构体中元素member的指针
((type *)0):将整数型0强制转换成结构体类型的指针;表示地址0
((type *)0)->member:该指针指向结构体元素member;
typeof( ((type *)0)->member ):获得结构体元素的类型
__mptr:__mptr是member类型的指向member地址的常量指针
所以,这一部分的作用就是:创建一个合适类型的常量指针指向结构体。

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

分析:
offsetof(type,member) :这个宏定义在就是获得结构体元素member的偏移量(字节为单位)
(char *)__mptr :将指向member的指针强制转换成char *类型,以便后面计算。
所以总的来说,这一部分的作用就是利用member的地址减去member的偏移量来计算结构体的地址,然后将结构体的地址转换成type *类型。

总结:

其实它的语法很简单,只是一些指针的灵活应用,它分两步:
第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。

/*
time:2020年8月31日14:55:17
objective:理解container_of宏
function:知道结构体中某变量的指针(地址)和偏移量offsetof(type,member)(&((type*)0)->member)
          反求结构体首地址
author:wu_junwu  
*/
#include<stdio.h>
//获得结构体中某变量member的偏移量
#define offsetof(type,member)((int)&((type*)0) -> member) 
/*
_mptr 是变量member的指针,强制转换类型为const typeof(((type*)0)->member)                                          
结构体的首地址,用(type*)强制转换
 type(m)的作用是由变量m可以得知变量m的数据类型
 */
#define container_of(ptr,type,member)( {  \
const typeof(((type*)0)->member) *_mptr=(ptr);(type*)((char*)_mptr - offsetof(type,member));}) 
//定义结构体
struct definestruct
{
	int a;
	char b;
	short c;
	long d;
};
//主函数
int main(void)
{
	struct definestruct ds;                //重命名结构体
	struct definestruct init_struct={1,'t',2,15};  //初始化结构体
	struct definestruct *ps=NULL;           //初始化指针ps,该指针用于指向结构体首地址
	short *p=&(ds.c);                         //定义指针p并初始化,该指针指向的是container_of宏中的已知的地址
	ps=container_of(p,struct definestruct,c);   //结构体地址ps
	printf("结构体的首地址=%p\n",ps);
	printf("&a=%p\n",&(ps->a));
	printf("&b=%p\n",&(ps->b));
	printf("&c=%p\n",&(ps->c));
	printf("&d=%p\n",&(ps->d));
	printf("a=%d\n",ps->a);
	printf("a=%d\n",ds.a);     //不能写成	printf("a=%d\n",ds->a);     
	printf("a=%d\n",init_struct.a);
	printf("b=%d\n",init_struct.b);
	printf("c=%d\n",init_struct.c);
	printf("d=%d\n",init_struct.d);
    return 0;
	
}

/*
conclusion:
	第一步:定义#define offsetof(type,member)(&((tye*)0)->member)
	第二步:定义#define container(ptr,type,member)({
	const typeof(((type*)0)->member) *_mptr=(ptr);\    //  变量member的指针为常量(const)
	(type*)((char*)_mptr - offsetof(type,member));})    //强制转换类型type*
	第三步:输出结构体首地址。
container宏的作用是求出结构体指针,然后结构体指针可以访问结构体中所有的变量member( 变量的地址或变量本身的值)

疑问;为什么每一次运行的printf("结构体的首地址=%p\n",ps);结果都不一样????



*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/782682
推荐阅读
相关标签
  

闽ICP备14008679号