转:container_of分析 研究内核的博客
源地址:http://blog.csdn.net/tigerjibo/article/details/8299589
1.container_of宏
1> Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。 2>接口: container_of(ptr, type, member) ptr:表示结构体中member的地址 type:表示结构体类型 member:表示结构体中的成员 通过ptr的地址可以返回结构体的首地址 3> container_of的实现: #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) 其实它的语法很简单,只是一些指针的灵活应用,它分两步: 第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。 说明:typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型《typeof关键字在linux 内核中很常见》 第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。 关于offsetof的用法可参见offsetof宏的使用。
2. 举例来说明container_of的使用
1>正确示例:
#include <stdio.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct test_struct { int num; char ch; float f1; }; int main(void) { struct test_struct *test_struct; struct test_struct init_struct ={12,'a',12.3}; char *ptr_ch = &init_struct.ch; test_struct = container_of(ptr_ch,struct test_struct,ch); printf("test_struct->num =%d\n",test_struct->num); printf("test_struct->ch =%c\n",test_struct->ch); printf("test_struct->ch =%f\n",test_struct->f1); return 0; } 执行结果: jibo@jibo-VirtualBox:~/cv_work/work/list/container_of $ ./main test_struct->num =12 test_struct->ch =a test_struct->ch =12.300000
2>错误示例:
#include <stdio.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct test_struct { int num; char ch; float f1; }; int main(void) { struct test_struct *test_struct; char real_ch = 'A'; char *ptr_ch = &real_ch; test_struct = container_of(ptr_ch,struct test_struct,ch); printf("test_struct->num =%d\n",test_struct->num); printf("test_struct->ch =%c\n",test_struct->ch); printf("test_struct->ch =%f\n",test_struct->f1); return 0; } 执行结果为: jibo@jibo-VirtualBox:~/cv_work/work/list/container_of1 $ ./main test_struct->num =0 test_struct->ch =A test_struct->ch =0.000000 注意,由于这里并没有使用一个具体的结构体变量,所以成员num和f1的值是不确定的。
- 上一篇:offset宏的讲解
1.offset宏讲解
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
对这个宏的讲解我们大致可以分为以下4步进行讲解:
地址强制 "转换" 为 TYPE结构类型的指针;
>((TYPE *)0)->MEMBER 访问TYPE结构中的MEMBER数据成员;
>&( ( (TYPE *)0 )->MEMBER)取出TYPE结构中的数据成员MEMBER的地址;
>(size_t)(&(((TYPE*)0)->MEMBER))结果转换为size_t类型。
呢?当然不是,我们仅仅是为了计算的简便。也可以使用是他的值,只是算出来的结果还要再减去该数值才是偏移地址。来看看如下的代码:
#include<stdio.h>
#defineoffsetof(TYPE, MEMBER) ((size_t) &((TYPE *)4)->MEMBER)
struct test_struct {
int num;
char ch;
float f1;
};
int main(void)
{
printf("offsetof (struct test_struct,num)=%d\n",offsetof(struct test_struct,num)-4);
printf("offsetof (structtest_struct,ch) =%d\n",offsetof(struct test_struct,ch)-4);
printf("offsetof (struct test_struct,f1)=%d\n",offsetof(struct test_struct,f1)-4);
return 0;
}
运行结果为:
jibo@jibo-VirtualBox:~/cv_work/work/list/offset $ ./main
offsetof (struct test_struct,num) =0
offsetof (struct test_struct,ch) =4
offsetof (struct test_struct,f1) =8
。
二.举例体会offsetof宏的使用:
#include<stdio.h>
#defineoffsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
struct test_struct {
int num;
char ch;
float f1;
};
int main(void)
{
printf("offsetof(struct test_struct,num) =%d\n",offsetof(struct test_struct,num));
printf("offsetof (structtest_struct,ch) =%d\n",offsetof(struct test_struct,ch));
printf("offsetof (struct test_struct,f1)=%d\n",offsetof(struct test_struct,f1));
return 0;
}
执行结果为:
jibo@jibo-VirtualBox:~/cv_work/work/list/offset $ ./main
offsetof (struct test_struct,num) =0
offsetof (struct test_struct,ch) =4
offsetof (struct test_struct,f1) =8
转:container_of分析 研究内核的博客的更多相关文章
- Linux内核分析第一周学习博客 --- 通过反汇编方式学习计算机工作过程
Linux内核分析第一周学习博客 通过反汇编方式学习计算机工作过程 总结: 通过这次对一个简单C程序的反汇编学习,我了解到计算机在实际工作工程中要涉及大量的跳转指针操作.计算机通常是顺序执行一条一条的 ...
- Linux内核分析第二周学习博客——完成一个简单的时间片轮转多道程序内核代码
Linux内核分析第二周学习博客 本周,通过实现一个简单的操作系统内核,我大致了解了操作系统运行的过程. 实验主要步骤如下: 代码分析: void my_process(void) { int i = ...
- angular源码分析 摘抄 王大鹏 博客 directive指令及系列
链接地址:http://www.cnblogs.com/web2-developer/p/angular-14.html $compile的功能:将一个html字符串或者一个DOM进行编译,返回一个链 ...
- core dump + LINUX 内核系列博客
参考:http://www.cnblogs.com/ahuo/category/72819.html http://blog.csdn.net/tenfyguo/article/details/815 ...
- Linux内核总结博客 20135332武西垚
http://www.cnblogs.com/wuxiyao/p/5220677.htmlhttp://www.cnblogs.com/wuxiyao/p/5247571.htmlhttp://www ...
- LINUX 内核学习博客
http://www.cnblogs.com/yjf512/category/385367.html
- 我的Android进阶之旅------>经典的大牛博客推荐(排名不分先后)!!
本文来自:http://blog.csdn.net/ouyang_peng/article/details/11358405 今天看到一篇文章,收藏了很多大牛的博客,在这里分享一下 谦虚的天下 柳志超 ...
- 一步步开发自己的博客 .NET版(3、注册登录功能)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
- hexo框架-next主题-github搭建个人博客
IT`huhui 的前言录 我在GITHUB的个人站点:http://ithuhui.cn 这里遇到的很多问题都是亲身解决后写的.还有遇到不懂可以邮件M我 在这里要感谢浮生志的博客教程,很多我一开始不 ...
随机推荐
- 基础(二):Linux系统/etc/init.d目录和/etc/rc.local脚本
原文来自http://www.ghacks.net/2009/04/04/get-to-know-linux-the-etcinitd-directory/ 译文来自http://blog.csdn. ...
- anaconda里的python版本回退, requirements
事情起因:我用的python3.7 , 同事机器学习的部分使用tensorflow,只支持python3.6, 所以我从3.7回退到3.6 conda create -n python36 pytho ...
- Java-Class-@I:lombok.extern.slf4j.Slf4j
ylbtech-Java-Class-@I:lombok.extern.slf4j.Slf4j 1.返回顶部 2.返回顶部 1. package com.ylbtech.api.controlle ...
- 杂项:SVN -u
ylbtech-杂项:SVN 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 7.返回顶部 8.返回顶部 9.返回顶部 10 ...
- MakeDown渲染出错
MakeDown渲染出错 makedown作为程序员不可或缺的编辑工具,平时的使用技巧也是非常多的. 今天给新电脑装了一个,发现出现了错误(win10环境下),如图: 错误的表现形式即:不能实时预览M ...
- 9、TestNG介绍与安装
介绍 TestNG是一个受JUnit和NUnit启发的测试框架,但引入了一些新功能,使其更加强大和易于使用,例如: 注释. 在任意大的线程池中运行你的测试,这些线程池有各种可用的策略(所有方法在他们自 ...
- Python 操作excel常见异常
一.使用xlrd模块读取excel: 1.报错:IndexError: list index out of range,如下图 解决方法:reading_sheet.cell(1,0).value中c ...
- swiper实现上下滑动翻页,内置内容页也滚动
如果我猜的没错,是全网(哈哈)比较少的成功解决方案,如需要转载,请声明并转载出处. swiper实现了上下滑动翻页,但是有几个页面的内容显示不完.如果一页显示不完时可以滑动查看,应该怎么做?这个是我多 ...
- JDK8新特性之Optional
Optional是什么 java.util.Optional Jdk8提供Optional,一个可以包含null值的容器对象,可以用来代替xx != null的判断. Optional常用方法 of ...
- spring 声明式事务原理解读
在Spring中,声明式事务是通过事务属性(transaction attribute)来定义的.事务属性描述了事务策略如何应用到方法上.事务属性包含5个方面: 传播行为 隔离级别 是否只 ...