tfref 

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

typedef struct{int a;int b;int c;
}ss;

  这是一个很简单的结构体, 没什么特殊的, 稍微分析下该结构体(假设在32位平台上):
    结构体的大小(字节):4+4+4=12字节
    成员a的偏移:0
    成员b的偏移:4
    成员c的偏移:8
  我们用ss来定义一个变量:
    ss s = {1,2,3};
  那么此时a,b,c的值分别为:a=1,b=2,c=3.
其实编译器在生成代码的时候其实是这样给成员变量赋值的:
  假定s的地址为:0x12000000, 则:
    *(int*)((char*)&s + 0) = 1;
    *(int*)((char*)&s + 4) = 2;
    *(int*)((char*)&s + 8) = 3;
  也就是说是在&s的地址基础上加上变量的偏移来确定成员的指针并赋值的, 所以:
    &s->a 将得到 0x12000000 + 0 = 0x12000000
    &s->b 将得到 0x12000000 + 4 = 0x12000004
    &s->c 将得到 0x12000000 + 8 = 0x12000008
  所以:    结构体的地址   +  成员变量的偏移 = 成员变量的地址
  移一下项:  成员变量的地址 -  成员变量的偏移 = 结构体的地址
  哇哇, 这就是我们想要的地址, 不就是做了个减法嘛~~~囧

  首先, 成员变量的地址是我们知道的.
  其次, 我们需要得到成员变量的偏移(假定为成员b的偏移).
    怎么办呢? 我们可以这样:
      &s->b - (unsigned long)&s, 这样就可以得到成员b的偏移了, 但是, 但是, &s 是我们需要的, 显然暂时是个未知数, 既然这样...
    那, 我们再做一次减法吧(非正确的C语言表达式, 不过结果没问题, 这里只是显得清楚点):
      &(s-s)->b - (unsinged long)&(s-s),
    其中, 为保证类型一致, 需要:
      s-s = (ss*)0
      (unsigned long)&(s-s) = (unsigned long)(ss*)0 = 0, 直接省略该部分就可以了
    那么, 化简得到: &((ss*)0)->b - (unsigned long)0
    最简结果: &((ss*)0)->b, 这就是b的偏移
  哈哈, 很简单吧, 0指针的妙用, 总共做了两次减法而已~ 对你们数学帝来说肯定不是问题啦~
  其中, 我们需要知道ss结构体的原型, ss结构体中的某个成员变量b(其实无论哪个都一样, 只是要和前面提供指针的那个变量要一致)

  总结下, 我们需要提供:结构体中某个成员变量的地址, 该结构体的原型, 该结构体中的某个成员变量(与前面要是同一个变量)

  最终的CONTAINING_RECORD的定义为:

#define CONTAINING_RECORD(addr,type,field) ((type*)((unsigned char*)addr - (unsigned long)&((type*)0)->field))  addr:  结构体中某个成员变量的地址  type:  结构体的原型  field: 结构体的某个成员(与前面相同)

  好了, 所有的结论都出来了, 这是一个万能公式, 不管成员变量是哪一个结果都正确, 这是相对于知道第一个变量的地址而言的:
    如果知道的是第一个成员的地址(pa = &s->a)的话, 这是最简单的情况了:
    直接强制类型转换就可以了: (ss*)pa 即可, 此时 &((type*)0)->field 这部分恰好为0
    所以结果直接就是((type*)addr)了, 最简单的情况. 也是我们最容易想到的一种情况, 比如把链表元素放在结构体的最开始 ~~~
  
  到这里这个CONTAINING_RECORD宏就已经说完了~  
  现在, 我们在使用LIST_ENTRY等双向链表时, 不管把该链表放在结构体的哪个地方, 都可以在遍历链表时通过CONTAINING_RECORD宏来准确得到整个结构体的地址了~
记得移除链表中的某个元素的时候, 要free整个结构体的地址才行哦, WDK提供的操作函数只是把该链表元素脱离整个链表~~~

btw:
  把addr转换为 unsigned char*的原因是在指针计算时的计算单位为1, 也就是说 (unsigned char*)addr+1 = addr+1, 不转换的话肯定是错误的
  把&((type*)0)->field转换为(unsigned long)4个字节宽的同时是要保证表达式不是由两个指针的算术操作构成的, 因为C语言标准未定义那样的运算

写了这么多, 希望没落下什么吧~
女孩不哭(QQ:191035066)@2013-01-07 18:56:57 http://www.cnblogs.com/memset

我对CONTAINING_RECORD宏的详细解释相关推荐

  1. MTK 驱动 (70)---MTK Projiectconfig.mk文件详细解释

    MTK Projiectconfig.mk文件详细解释 AUTO_ADD_GLOBAL_DEFINE_BY_NAME AUTO_ADD_GLOBAL_DEFINE_BY_VALUE AUTO_ADD_ ...

  2. Linux下函数调用堆栈帧的详细解释【转】

    转自:http://blog.chinaunix.net/uid-30339363-id-5116170.html 原文地址: Linux下函数调用堆栈帧的详细解释 作者:cssjtuer http: ...

  3. 视频采集相关知识之YUV格式详细解释

    原文出处:http://hi.baidu.com/yrworld/item/43e8bfd9e6978018d78ed098 YUV格式详细解释 概述 YUV(亦称YCrCb)是被欧洲电视系统所采用的 ...

  4. Python精讲Numpy基础,大牛笔记详细解释

    https://www.toutiao.com/a6664936105076326920/ 总认为Numpy是渣渣,直到深入接触以后才知道功能这么强大.堪比Matlab啊.果然是人生苦短,我用Pyth ...

  5. UIApplication sharedApplication详细解释-IOS

    UIApplication sharedApplication详细解释-IOS 分类: iOS开发2012-07-27 10:25 10287人阅读 评论(2) 收藏 举报 applicationui ...

  6. MongoDB:详细解释mongodb的高级操作,聚合和游标

    前几天总结了mongodb的安装入门.详细解释了增删改查的基本操作,今天再来总结下mongodb更高级的操作,聚合和游标. 一.聚合,mongodb的聚合操作一般分为四种情景,分别是:count.di ...

  7. PySide2 基础入门-创建实例窗口(详细解释)

    PySide2 基础入门-创建实例窗口(详细解释) python 3.7 / Pyside2 (如果使用pyQt5,将Pyside2 直接替换PyQt5即可)首先我们在Qt Designer中画好界面 ...

  8. Python之pandas:pandas.set_option函数的参数详细解释

    Python之pandas:pandas.set_option函数的参数详细解释 目录 pandas.set_option函数的参数解释 函数API:pandas.set_option pandas. ...

  9. linux中useradd的文件路径,linux的useradd命令详细解释

    Linux中的useradd命令顾名思义就是添加用户的命令.下面由学习啦小编为大家整理了Linux的useradd命令的详细解释的相关知识,希望对大家有帮助! linux的useradd命令的详细解释 ...

最新文章

  1. jsapi设计_一个简单API设计
  2. 怎么用python画简单的图-用python进行简单的画图操作
  3. 从家书到小票!看到海尔智家的转型是真的
  4. linux——虚拟机的图形安装、管理以及快照
  5. Eclipse配置工程自动执行ant实现热部署
  6. uva 10692——Huge Mods
  7. mysql导出数据库对象命令_mysql数据库导出数据(命令)
  8. 从系统中取得指定资源图像(转载)
  9. java 托盘开发_基于java开发之系统托盘的应用
  10. css链接,列表,表格
  11. java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal问题解决
  12. Leetcode每日一题:面试题17.12 binode
  13. 误用mysql保留字做表名,导致报错
  14. mysql 版本_mysql各个版本介绍
  15. 有人30岁转型做Android开发,老罗android开发视频教程
  16. 合并时显示是无效的m3u8文件_如何合并m3u8及ts文件
  17. 从 SEC EDGAR 获取股东治理数据 (Shareholder Activism)
  18. 【终结版】小家电安规要求以及世界各国安规认证知识分享
  19. TikTok选品有什么技巧?
  20. 鸡兔同笼python程序怎么写_鸡(土从)

热门文章

  1. 教机器遗忘或许比学习更重要:让AI健忘的三种方式
  2. 基于互联网云脑架构分析百度的现状与未来
  3. 前 Google 工程师总结的算法面试指南
  4. 三分钟黑了阿里?马云下死命令留他?吴翰清辟谣:我没黑过阿里
  5. Ztree节点增加删除修改和Icheck的用法
  6. jsonView谷歌插件
  7. Linux_Shell_ Map 的使用和遍历
  8. iOS GCD_1
  9. Python基础学习之 函数
  10. 螳螂捕蝉黄雀在后!地下黑客论坛免费远控木马被曝“后门”