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. centos7下编译qt的mysql驱动

    在编译mysql驱动之前,首先要安装mysql,可以使用yum安装,这里将不再介绍. 在将qt和mysql都安装好之后,首先找到mysql的头文件以及他的共享库,我的mysql是使用yum安装的,头文 ...

  2. A-frame_02

    A-Frame 让我们能够仅仅通过几行HTML代码创建出可以运行在桌面, 虚拟眼镜, 以及手机上的VR场景. 而且因为这个框架是基于HTML的, 我们也可以像一般的HTML元素一样配合JavaScri ...

  3. sae-多个file_put_contents('saestor://public/text.txt',$data);只写第一次

    多个file_put_contents('saestor://public/text.txt',$data); 只执行第一个文件的写入,永久存储也只需要一次写入 如果需要用户中间缓存文件,用tmpfs ...

  4. hdu 4550 卡片游戏 贪心

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4550 题意:有n(n <= 100)个0~9之间的卡片,从左往右将卡片放到之前的卡片最左边或者最 ...

  5. UIExtendedEdge

    在IOS7以后 ViewController 开始使用全屏布局的,而且是默认的行为通常涉及到布局.就离不开这个属性 edgesForExtendedLayout,它是一个类型为UIExtendedEd ...

  6. C# dynamic

    [TestMethod] public void DynamicTest() { dynamic Customer = new ExpandoObject(); Customer.Name = &qu ...

  7. theano log softmax 4D

    def softmax_4d(x_4d): """ x_4d: a 4D tensor:(batch_size,channels, height, width) &quo ...

  8. portlet初学习及HelloWorld例子

    1. 在myeclipse中新建一个web project,在src中新建如下类: package com.yoyo.portlet; import java.io.IOException; impo ...

  9. 玩转AWS CloudWatch微信告警

    做海外业务时大多使用亚马逊 AWS 服务,配套AWS 监控 CloudWatch 功能强大,如果能和微信结合就更棒了.现在分享下如何玩转 CloudWatch 微信通知. AWS EC2 云主机配套的 ...

  10. MYSQL数据库根据data文件中的.frm和ibd文件恢复单表数据

    数据库误操作,把表的字段删除了,关键是被删除的字段的数据很重要,现在想要恢复数据,下面说说是怎么操作的. 数据库只剩.frm和.ibd文件了,按照网上的做法分如下两步来进行:一.找回表结构,二.找回数 ...