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. Newtonsoft.Json随手记

    private static Newtonsoft.Json.JsonSerializerSettings CreateSettings(string dateFormat) { Newtonsoft ...

  2. 【HeadFirst设计模式】8.模板方法模式

    模板方法 定义: 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使用得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 策略模式: 定义一个算法家族,并让这些算法可以互 ...

  3. html+ashx 缓存问题

    最近采用html+ashx的方式做了一个项目的几个配置页面的功能,由于浏览器的缓存问题,每次更新数据提交后,页面总是不会刷新,也就是说除了第一次加载页面会向一般处理(ashx)拿数据外,其他情况都是优 ...

  4. dataTable 禁止排序

    $("#id").DataTable({ "ordering": false, // 禁止排序 });

  5. 使用imp加载python模块

    import impimport sysfn_, path, desc = imp.find_module('mymodule', ['/data/module/'])print fn_,path,d ...

  6. Style 的优先级

    Dependency Property(简称DP)是WPF的核心,Style就是基于Dependency Property的,关于DP的内幕,请参见深入WPF--依赖属性.Style中的Setter就 ...

  7. Logback 简单使用

    1.Logback为取代log4j而生 Logback是由log4j创始人Ceki Gülcü设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- cl ...

  8. RS232转RS485电路图分析

    在电子发烧友网站上,看到RS232转RS485的一个电路图,如下图所示.元件主要是HN232CP和MAX485CPA,也就是TTL转232电路和TTL转485电路的结合体.可是这个电路却不好分析,几经 ...

  9. 加解密算法二:非对称加解密及RSA算法的实现

    加密和解密使用不同的密钥的一类加密算法.这类加密算法通常有两个密钥A和B,使用密钥A加密数据得到的密文,只有密钥B可以进行解密操作(即使密钥A也无法解密):相反,使用密钥B加密数据得到的密文,只有密钥 ...

  10. dtv_driver.ko

            替换dtv_driver.ko .步骤:         shell@android:/ # get_rootfs.sh                                 ...