container_of深入理解

container_of在linux头文件kernel.h中定义,如下:

  14#ifndef offsetof15#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)16#endif1718#ifndef container_of19/**20 * container_of - cast a member of a structure out to the containing structure21 * @ptr:        the pointer to the member.22 * @type:       the type of the container struct this is embedded in.23 * @member:     the name of the member within the struct.24 *25 */26#define container_of(ptr, type, member) ({                      /27        const typeof(((type *)0)->member) * __mptr = (ptr);     /28        (type *)((char *)__mptr - offsetof(type, member)); })29#endif
这里在简单插入对typeof的理解:
typeof关键字是C语言中的一个新扩展。从语义上看,typeof 关键字将用做类型名(typedef名称)并指定类型。
请注意,typeof构造中的类型名不能包含存储类说明符,如externstatic。不过允许包含类型限定符,如constvolatile
例如:

  1. struct demo_struct {
   2.     type1 member1;
   3.     type2 member2;
   4.     type3 member3;
   5.     type4 member4;
   6. };
   7.
   8. struct demo_struct demo;

   struct demo_struct *demop = container_of(memp, struct demo_struct, member3);
首先,我们将container_of(memp, struct demo_struct, type3)根据宏的定义进行展开如下:
   1. struct demo_struct *demop = ({                      /
   2.     const typeof( ((struct demo_struct *)0)->member3 ) *__mptr = (memp);    /
   3.     (struct demo_struct *)( (char *)__mptr - offsetof(struct demo_struct, member3) );})

假设结构体变量demo在实际内存中的位置如下图所示:
     demo
+-------------+ 0xA000
|   member1              |
+-------------+ 0xA004
|   member2             |
|                                |
+-------------+ 0xA010
|   member3             |
|                                |
+-------------+ 0xA018
|   member4             |
+-------------+
则,在执行了上述代码的第2行之后__mptr的值即为0xA010。

同样,我们将上述的offsetof调用展开,即为:
   3. (struct demo_struct *)( (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) );
可见,offsetof的实现原理就是取结构体中的域成员相对于地址0的偏移地址,也就是域成员变量相对于结构体变量首地址的偏移。
因此,offsetof(struct demo_struct, member3)调用返回的值就是member3相对于demo变量的偏移。结合上述给出的变量地址分布图可知,offsetof(struct demo_struct, member3)将返回0x10。
于是,由上述分析可知,此时,__mptr==0xA010,offsetof(struct demo_struct, member3)==0x10。
因此, (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) == 0xA010 - 0x10 == 0xA000,也就是结构体变量demo的首地址(如上图所示)。

转载于:https://www.cnblogs.com/p2liu/archive/2011/05/24/6048784.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/435043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

正在读取软件包列表... 有错误!

正在读取软件包列表... 有错误!E: Encountered a section with no Package: headerE: Problem with MergeList /var/lib/apt/lists/cn.archive.ubuntu.com_ubuntu_dists_natty_main_i18n_Translation-enE: 无法解析或打开软件包的列表或是状态文件。问题&#xff1a…

2021-10-19

下载的工具箱 找到下载工具箱位置 打开工具箱属性 出现错误1 无法启动配置 RasterCommander.ImageServer 解决方法

python自动控制库_Python最为神奇的库,可控制你的鼠标键盘自动运行!

Python最为神奇的库,可控制你的鼠标键盘自动运行!这个库让你可以控制和监控输入设备。喜欢我还有更多干货入门知识,来公众号『程序员中文社区』聊聊吧。Python最为神奇的库,可控制你的鼠标键盘自动运行!对于每一种输入…

iframe 自适应高度 跨域

window.navigator.Allframesnull;window.navigator.Allframes { iframe1: window }; //根据页面name属性查找到子页面所在Ifame对象 window.navigator.getFrameByNamefunction(oName){ return this.Allframes[oName] }; //将一个Iframe对象注册到window.navigator.Al…

【转】Windows服务调试技巧

关于调试windows service, 其实这是一个老生常谈的问题了. 通常的处理办法是, 在service运行后, 在调试器中选择attach to process. 然而这种做法也有一定的局限性, 例如在service启动时的OnStart事件中的代码, 基本上很难调试. 往往当attach到我们的service的时候, 这部分代码…

visual studio 没有属性页_驯龙物语10月14日更新|新增快捷购买页签

更新公告大家好,我是小白龙,很高兴又与大家见面啦!维利克洛大陆又迎来了新内容,守护者们要仔细阅读看到最后喔!更新时间本次更新于10月14日6:00-7:00进行,视更新进度可能提前开服或顺延,各位守护…

JDK1.6

JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛的Java SDK。JDK 是整个Java的核心,包括了Java运行环境,Java工具和Java基础的类库。 java环境变量配置: 如果是Window…

AE开发右键缩放至图层

添加 右键的控件 将控件添加至axtoccontrol 双击进入点击事件 private void 缩放至图层ToolStripMenuItem_Click(object sender, EventArgs e){axMapControl1.ActiveView.FullExtent = m_Layer.AreaOfInterest;axMapControl1.ActiveView.Refresh();axTOCControl1.Update();}…

快速幂取余

快速幂取模算法,留着以后慢慢研究 long long modExp(long long a,long long b,long long n){ long long t,y; t 1; y a; while(b){ if(b % 2) t t * y % n; y y * y % n; b >> 1; } return t;} 转载于:https:/…

nginx源码学习资源

nginx源码学习是一个痛苦又快乐的过程,下面列出了一些nginx的学习资源。 首先要做的当然是下载一份nginx源码,可以从nginx官方网站下载一份最新的。 看了nginx源码,发现这是一份完全没有注释,完全没有配置文档的代码。 现在你最希…

C#打开文件和文件夹

打开文件夹 private void buttonX2_Click(object sender, EventArgs e){//输出文件路径FolderBrowserDialog dialog new FolderBrowserDialog();//提示用户打开文件窗体dialog.Description "请选择文件路径";if (dialog.ShowDialog() DialogResult.OK){textBoxsav…

通过JavaScript操作HTML中select标签

添加: Js代码1.function selectChange() 2.{ 3. var seldocument.getElementById("select1"); 4. Option option new Option("Text","Value"); 5. sel.add(option); 6.} function selectChange(){ var seldocument.get…

标签机二次开发

1. BPLA_OpenComEx("com1",38400,1,1000) 打开串口 2. BPLA_Set(2,0,1) 设置打印机基本参数,如果设置出纸方式为“撕离”,那么需要第3.1步,如果设置出纸方式为“回卷”,需要第3.2步 如果打印机有碳带,需要设…

动漫的python语言代码大全_下载动漫壁纸-Python代码

本帖最后由 我心她有丶 于 2020-4-16 19:28 编辑前段时间在论坛找到一个下载动漫壁纸的软件,还挺好用的,这几天突然用一下,下载不出图片,下载的一片白,然后分析了下他的软件,得到了一个地址: ht…

安装包卸载时如何删除安装时写在系统环境变量中的内容

在用InstallShield制作安装包时,有时我们会在脚本中通过操作注册表,配置系统环境变量,比如在Path中追加,但卸载时如何清除追加的路径变量,一直有些模糊。 今天受网友启发,在InstallShield的帮助文档中找到了…

AE点击按钮添加栅格

private void buttonX3_Click(object sender, EventArgs e){OpenFileDialog pOpenFileDialog = new OpenFileDialog();pOpenFileDialog.CheckFileExists = true;pOpenFileDialog.Title = "添加栅格文件";pOpenFileDialog.Filter = "栅格数据(*.tiff;*.tif;*.jpe…

深入浅出VC++串口编程之基于Win32 API

1、API描述在WIN32 API中,串口使用文件方式进行访问,其操作的API基本上与文件操作的API一致。打开串口Win32 中用于打开串口的API 函数为CreateFile,其原型为:HANDLE CreateFile (  LPCTSTR lpFileName, //将要打开的串口逻辑名&…

关于Visual C#装箱与拆箱的研究

在对这个问题展开讨论之前,我们不妨先来问这么几个问题,以系统的了解我们今天要探究的主题。  观者也许曾无数次的使用过诸如System.Console类或.NET类库中那些品种繁多的类。那么,我想问的是它们究竟源自何处?C#又是如何联系它…