关于宏: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语言)翻译成汇编语言时起作用,这个很重要,稍后会 ...
随机推荐
- AJAX提交表单后要清空,否则再次提交原来的数据会认为重复提交,提交失败。使用ajaxSubmit 函数需要引入jquery.form.min.js 文件
<script src="../../Scripts/js/jquery.form.min.js" type="text/javascript">& ...
- BZOJ1821 [JSOI2010]Group 部落划分 Group 【最小生成树】
题目 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成为谜团了--聪聪根 ...
- mysql的乐观锁和悲观锁
悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个非常基础的概念.本文将对这两种常见的锁机制在数据库数据上的实现进行比较系统的介绍. 悲观锁(Pessimistic Lock) 悲观锁的 ...
- server reached pm.max_children setting (5), consider raising it
先查看日志 /data1/server/php-cgi/var/log/php-fpm.log[19-Dec-2012 11:41:13] WARNING: [pool www] server rea ...
- hdu 4388 Stone Game II sg函数 博弈
Stone Game II comes. It needs two players to play this game. There are some piles of stones on the d ...
- mysql 逻辑架构(三层)
1.客户端(主要处理连接,授权认证,安全等). 2.MYSQL服务器层(核心服务功能都在这层,包括,查询解析,分析,优化,缓存以及所有的内置函数,所有跨存储引擎的功能都在这层实现:存储过程,触发器,视 ...
- sqlmap注入一般步骤
1. 找到注入点url2. sqlmap -u url -v 1--dbs 列出数据库或者 sqlmap -u url -v 1 --current-db 显示当前数据库3. sqlmap -u ur ...
- selenium访问百度 然后获取百度logo的截图
#!/usr/bin/env python # encoding: utf-8 import time from selenium import webdriver from PIL import I ...
- 为何url地址不是直接发送到服务器,而是被编码后再发送
首先,先说一下,关于为何必须将url地址,去编码后,再发送,是因为相关的协议规范:RFC 1738,定义了url地址中不能包含除了0-9的数字,大小写字母(a-zA-Z),短横线’-‘ 之外的字母.换 ...
- django使用mysql的设置与迁移
1.创建数据库 create database django_lianxi charset=utf8; 2.django项目文件夹的setting.py设置 Django项目默认 sqlite3 数据 ...