关于宏: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的更多相关文章
- linux内核第一宏 container_of
内核第一宏 list_entry()有着内核第一宏的美称,它被设计用来通过结构体成员的指针来返回结构体的指针.现在就让我们通过一步步的分析,来揭开它的神秘面纱,感受内核第一宏设计的精妙之处. 整理分析 ...
- linux内核中宏container_of是干什么的?
Linux Kernel Version 4.14 1. container_of是干什么的? 已知一个结构体中某个成员的首指针,那么就可以通过宏container_of来获得此结构体的首指针 2 先 ...
- container_of 和 offsetof 宏详解
在linux内核链表中,会遇到两个宏. 在include/linux/stddef.h中,有这样的定义 #define offsetof(TYPE, MEMBER) ((size_t) &(( ...
- linux内核宏container_of
首先来个简单版本 /* given a pointer @ptr to the field @member embedded into type (usually * struct) @type, r ...
- (十)Linux内核中的常用宏container_of
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...
- Linux内核中的常用宏container_of
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...
- Linux内核中的常用宏container_of其实很简单【转】
转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...
- 剖析linux内核中的宏---------container_of
#define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...
- linux内核宏container_of前期准备之gcc扩展关键字typeof
typeof基本介绍 typeof(x) 这是它的使用方法,x可以是数据类型或者表达式.它的作用时期和sizeof类似,就是它是在编译器从高级语言(如C语言)翻译成汇编语言时起作用,这个很重要,稍后会 ...
随机推荐
- user namespace 2
昨天又试了一下, echo 0 1000 1 > /proc/<PID>/uid_map 想着直接把一个进程的uid设置成root,这样他就可以在自己的user namespace ...
- uoj169:元旦老人与数列
题意:http://uoj.ac/problem/169 sol :线段树..........蜜汁TLE了一个点,不管了..... 代码抄snowMyDream的,orz........... 线段 ...
- spring3创建RESTFul Web Service
spring 3支持创建RESTFul Web Service,使用起来非常简单.不外乎一个@ResponseBody的问题. 例如:后台controller: 做一个JSP页面,使用ajax获取数据 ...
- CF10D LCIS (动态规划)
题目链接 Solution 动态规划. 令 \(f_{i,j}\) 表示 \(a\) 数组前 \(i\) 个和 \(b\) 数组前 \(j\) 所得的最长的 LCIS . 转移很好想: \(a_i!= ...
- vs2008升级正式版
1.VS2008简体中文正式版序列号 1.Visual Studio 2008 Professional Edition: XMQ2Y-4T3V6-XJ48Y-D3K2V-6C4WT 2.Visual ...
- Hibernate中多种方式解除延迟加载
问题引发:因为dao使用load(),默认延迟加载的,当在biz关闭session之后,UI层无法获取对象的非id属性值 解决方案: 1.变成get,即时加载 2.用Hibernate.isIniti ...
- 杭电oj2032、2040、2042、2054、2055
2032 杨辉三角 #include <stdio.h> int main(){ ][],i,j,n; while(~scanf("%d",&n)){ ;i& ...
- CRichEditCtrl 输入字符串长度限制
1.我用 CRichEditCtrl 控件,发现它通过代码可以向里面写大于 32KB 的字符,但手工却只能输入小于 32767 个字符,再多则自动舍弃. 2.初始化时调用CRichEditCtrl:: ...
- PHP开发
php.ini error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_CORE_WARNING & ~E_NOT ...
- 9.OpenStack安装web界面
安装仪表板 安装仪表板组件 yum install -y openstack-dashboard httpd mod_wsgi memcached python-memcached 编辑/etc/op ...