关于宏:container_of和 offsetof以及list_for_each_entry
Posted 唯一诺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于宏:container_of和 offsetof以及list_for_each_entry相关的知识,希望对你有一定的参考价值。
1.offsetof(TYPE, MEMBER)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
offsetof是一个自定义的宏,其返回值是一个member成员在一个type类型的结构体中相对于结构体首地址的字节偏移量;
分析其工作原理:
1.(TYPE *)0将0地址强制转换成TYPE *类型指针---------且可以认为,这个类型的结构体的首地址是0x0;
2.(TYPE *)0->MEMBER以指针形式访问成员MEMBER;
3.&((TYPE *)0->MEMBER)取成员MEMBER的地址;
因为是从0地址开始的,所以取得成员变量MEMBER的地址等于=相对与结构体首地址的偏移地址;
4.((size_t) &((TYPE *)0)->MEMBER),然后将强制类型转换成int型,作为offsetof的返回值;
2.container_of
#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) * __mptr = (ptr);(type *)( (char *)__mptr - offsetof(type,member) );})
作用:根据一个结构体变量中的一个域成员变量的指针(也就是地址)来获取指向整个结构体变量的指针(地址)的功能
分析:
1).const typeof( ((type *)0)->member ) * __mptr = (ptr)
typeof( ((type *)0)->member )这里获得member成员的类型;
typeof()就是由变量名得到变量数据类型的;
2).const typeof( ((type *)0)->member ) * __mptr = (ptr)
定义一个const typeof() * __mptr类型的指针,并初始化为ptr;这里的ptr是一个指向type类型结构体成员变量member的指针,也就是member在结构体中的地址;
3).(char *)__mptr
这里将__mptr指针强制类型转换成char *类型:
原因是: 如果_mptr为int *类型, _mptr - offset 相当于减去 sizeof(int)*offset个字节;
4).offsetof(type,member)
就是一个得到member相当于结构体首地址的偏移量,以字节单位;
5).(char *)__mptr - offsetof(type,member)
得到_mptr所在结构体的首地址;
6).(type *)( (char *)__mptr - offsetof(type,member))
将得到的结构体首地址强制类型转换成type *类型;
3.list_for_each_entry
#define list_for_each_entry(pos, head, member) for (pos = list_entry((head)->next, typeof(*pos), member); prefetch(pos->member.next), &pos->member != (head); pos = list_entry(pos->member.next, typeof(*pos), member))
在这里,list_for_each_entry就是一个for循环:
for ( pos = list_entry((head)->next, typeof(*pos), member); prefetch(pos->member.next), &pos->member != (head); pos = list_entry(pos->member.next, typeof(*pos), member))
1) pos = list_entry((head)->next, typeof(*pos), member)
其中:
#define list_entry(ptr, type, member) container_of(ptr, type, member)
因此:
pos = list_entry((head)->next, typeof(*pos), member) 等价于: pos = container_of((head)->next, typeof(*pos), member)
所以:pos被初始化为一个指向 结构体成员变量member所在的结构体(结构体类型为typeof(*pos)) 的指针;
由于container_of的第一个参数是head->next,所以被初始化的pos是指向头结点的下一个节点;
2) prefetch(pos->member.next), &pos->member != (head)
判断是否又到达头结点,表明遍历结束
3) pos = list_entry(pos->member.next, typeof(*pos), member)
是pos指向下一个链表节点;
以上是关于关于宏:container_of和 offsetof以及list_for_each_entry的主要内容,如果未能解决你的问题,请参考以下文章