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的更多相关文章

  1. linux内核第一宏 container_of

    内核第一宏 list_entry()有着内核第一宏的美称,它被设计用来通过结构体成员的指针来返回结构体的指针.现在就让我们通过一步步的分析,来揭开它的神秘面纱,感受内核第一宏设计的精妙之处. 整理分析 ...

  2. linux内核中宏container_of是干什么的?

    Linux Kernel Version 4.14 1. container_of是干什么的? 已知一个结构体中某个成员的首指针,那么就可以通过宏container_of来获得此结构体的首指针 2 先 ...

  3. container_of 和 offsetof 宏详解

    在linux内核链表中,会遇到两个宏. 在include/linux/stddef.h中,有这样的定义 #define offsetof(TYPE, MEMBER) ((size_t) &(( ...

  4. linux内核宏container_of

    首先来个简单版本 /* given a pointer @ptr to the field @member embedded into type (usually * struct) @type, r ...

  5. (十)Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  6. Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  7. Linux内核中的常用宏container_of其实很简单【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...

  8. 剖析linux内核中的宏---------container_of

    #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...

  9. linux内核宏container_of前期准备之gcc扩展关键字typeof

    typeof基本介绍 typeof(x) 这是它的使用方法,x可以是数据类型或者表达式.它的作用时期和sizeof类似,就是它是在编译器从高级语言(如C语言)翻译成汇编语言时起作用,这个很重要,稍后会 ...

随机推荐

  1. 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

    题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...

  2. BZOJ1079 [SCOI2008]着色方案 【dp记忆化搜索】

    题目 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块. 所有油漆刚好足够涂满所有木块,即c1+c2+-+ck=n.相邻两个木块涂相同色显得很难看 ...

  3. 【CF Round 439 B. The Eternal Immortality】

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  4. font-family 定义的最后为什么要加一句sans-serif

    定义font-family时,最好在最后加一个sans-serif,这样如果所列出的字体都不能用,则默认的sans-serif字体能保证调用; W3C建议字体定义的时候,最后以一个类别的字体结束,例如 ...

  5. ASIHttprequest-创建同步请求

    ASIHttprequest-创建同步请求 当你发送一个同步请求后,该请求会在当前的应用主线程中运行并获取程序的控制权限,也就说你的程序处于锁定的状态,在这个期间,你进行不了任何的操作,直到该请求返回 ...

  6. [ CodeVS冲杯之路 ] P1098

     不充钱,你怎么AC? 题目:http://codevs.cn/problem/1098/ 显然就是使每堆牌达到总体的平均数,尽量使每次移动时的牌数最大,这就类似于飞行棋,将几个棋子叠起来一起走是最优 ...

  7. [ CodeVS冲杯之路 ] P1501

     不充钱,你怎么AC? 题目:http://codevs.cn/problem/1501/ 水题一道 直接dfs,记录上当前深度,到了叶子节点就更新答案,并且每个节点将当前深度的计数+1,答案即为ma ...

  8. Error C1189: #error: Please use the /MD switch for _AFXDLL builds(转)

    原文转自 https://www.cnblogs.com/zwh0214/p/6048360.html 在VS 2013中编译程序时出现错误: 错误提示1: error C1189: #error : ...

  9. zabbix报警邮件qq邮箱收不到的问题

    出现这样问题的根本原因是因为zabbix对中文支持不太友好,乱码导致了邮件无法正常接收. 一.解决zabbix邮件内容为附件 1.安装发送邮件的mailx 以及windows文件转unix文件的命令 ...

  10. hdu 3790(SPFA)

    最短路径问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...