Windows中提供了一个宏

#define CONTAINING_RECORD (address, type, field ) ((type *)( \
(PCHAR)(address ) - \
(ULONG_PTR)(&((type *)0)->field)))

  

address : 结构体内成员实际地址
type : 结构体类型
field : 结构体内成员字段名称
 
作用: 更加提供的结构体成员地址反推结构体实例的地址。
 
宏进行的操作实际是:成员变量实际地址 - 成员变量偏移量。
 
大家可能对成员变量偏移量求解比较迷惑,首先假设一个结构体实例地址是从0开始分布的,由于成员变量的地址=结构体实例地址 + 成员变量偏移量,当结构体实例地址为0时,其指向的成员变量的地址就是成员变量的再结构体中的偏移量。
 
这技巧太NB了,不过大家可能还会有个疑惑,这个访问为什么不会出现内存越界问题呢?我刚看到时,第一反应是,为什么没有越界,后来仔细一想,哎,感叹自己对C语言的理解还不够透彻,其实后面计算偏移量时,虽然我们使用了地址0,
 
但是我们并没有存取地址中的任何值。如果我们直接把((type *)0)->field))赋值给另一个变量结构非法内存访问。
 
我们仔细捋下整个操作:
1、((type*)0) 以地址0转换为结构体实例的地址。
2、&(((type*)0)->field) 取字段field的地址,((type*)0)->field这个操作如果我们用它对其他变量赋值则直接出错,否则这只是个空操作什么也没有肯定不会出错,接着我们进行的取地址操作,这个操作相当于只是在结构体的地址基础上增加field变量的偏移量,因此根本不错在访问内存中内容的情况,只是单纯的对地址进行操作,看到这里应该理解了。
3、(ULONG_PTR)(&((type *)0)->field)))最后的转换只是为了字节对齐,使地址足够长。
 
通过汇编,我们看到其实后面求成员变量的偏移量在编译的时候编译器已经算计算好了。

CONTAINING_RECORD 宏的更多相关文章

  1. 我对CONTAINING_RECORD宏的详细解释

    宏CONTAINING_RECORD的用处其实还是相当大的, 而且很是方便, 它的主要作用是: 根据结构体中的某成员的指针来推算出该结构体的指针! 下面从一个简单的例子开始说起: 我们定义一个结构体, ...

  2. IOCP入门

    完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...

  3. 第10章 同步设备I/O和异步设备I/O(4)_利用I/O完成端口实现Socket通信

    I/O完成端口原理见上一篇(可点击这里) 10.5.4.4 利用I/O完成端口实现Socket通信 (1)Accept和AcceptEx流程的比较 ①采用accept方式的流程示意图如下(普通的阻塞函 ...

  4. 《天书夜读:从汇编语言到windows内核编程》七 内核字符串与内存

    1)驱动中的字符串使用如下结构: typedef struct _UNICODE_STRING{ USHORT Length; //字符串的长度(字节数) USHORT MaximumLength; ...

  5. Windows内存管理(1)--分配内核内存 和 使用链表

    1.      分配内核内存 Windows驱动程序使用的内存资源非常珍贵,分配内存时要尽量节约.和应用程序一样,局部变量是存放在栈空间中的.但栈空间不会像应用程序那么大,所以驱动程序不适合递归调用或 ...

  6. C++小技巧之CONTAINING_RECORD

    CONTAINING_RECORD Containing record是一个在C++编程中用处很大的一种技巧,它的功能为已知结构体或类的某一成员.对象中该成员的地址以及这一结构体名或类名,从而得到该对 ...

  7. Visual Studio 宏的高级用法

    因为自 Visual Studio 2012 开始,微软已经取消了对宏的支持,所以本篇文章所述内容只适用于 Visual Studio 2010 或更早期版本的 VS. 在上一篇中,我已经介绍了如何编 ...

  8. VC 中与字符串相关的宏 _T、TEXT,_TEXT、L 的作用

    CSDN原博文:http://blog.csdn.net/houkai363/article/details/8134787 遇到了:不能将参数 1 从“const char [5]”转换为“LPCT ...

  9. 【转】linux内核中writesb(), writesw(), writesl() 宏函数

    writesb(), writesw(), writesl() 宏函数 功能 : writesb()    I/O 上写入 8 位数据流数据 (1字节) writesw()   I/O  上写入 16 ...

随机推荐

  1. 出力csv

    public static void ExportResultLog(System.Data.DataTable dt, string fileName, string path) { if (!Sy ...

  2. Android开发系列之Android项目的目录结构

    今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目 ...

  3. div之间有间隙以及img和div之间有间隙的原因及解决方法

    原因: div 中 存在 img标签,由于img标签的 display:inline-block 属性. display:inline-block布局的元素在chrome下会出现几像素的间隙,原因是因 ...

  4. 很不错的NGINX URL重写实例

    转自:http://www.jbxue.com/article/2187.html 本文介绍nginx URL重写的相关知识,包括301重定向的内容等,希望对大家有所帮助. nginx rewrite ...

  5. SQL技术内幕二DDL

    创建数据库: if db_id('DBTest') is nullcreate database DBTest 创建表 use eb_fy_data_test---use 切换所在数据库上下文 if ...

  6. R语言语法笔记

    ## 1. 数据输入 ## a$b # 数据框中的变量 a = 15 # 赋值 a <- 15 # 赋值 a = c(1,2,3,4,5) # 数组(向量) b = a[1] # 数组下标,从1 ...

  7. struts2处理.do后缀的请求

    默认情况下,struts2是无法处理以.do为后缀的请求url的(默认情况下是.action或者不填,可以参见org.apache.struts2包下的default.properties文件). 但 ...

  8. Django数据库配置

    将Django使用数据库由默认的sqlite3更改为mysql: 1.安装mysql驱动程序 MySQLdb(mysql-python) mysqlclient Connector/Python Py ...

  9. com.mchange.v2.c3p0.ComboPooledDataSource

    C3P0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSourc ...

  10. 关于oi

    2015-12-26 今天在机房,楼上的孩子发下来一个exe,善良无知的我打开了那个exe,然后电脑就关机了.萌萌的辅导老师看到之后就不再萌萌哒,他跑到五楼训斥了那群孩子们一顿(自行脑补).出于报复, ...