Linux内核中的常用宏container_of其实很简单【转】

转自:http://blog.csdn.net/npy_lp/article/details/7010752

开发平台:Ubuntu11.04

    编 译器:gcc version 4.5.2 (Ubuntu/Linaro4.5.2-8ubuntu4)

 

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址。

    Container_of的定义如下: 

[cpp] view plain copy
  1. #define container_of(ptr, type, member) ({      \  
  2.     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \  
  3.     (type *)( (char *)__mptr - offsetof(type,member) );})  

    其实它的语法很简单,只是一些指针的灵活应用,它分两步:

    第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。

    第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。

    其中的语法难点就是如何得出成员相对结构体的偏移量?

    通过例子说明,如清单1: 

[cpp] view plain copy
  1. /* linux-2.6.38.8/include/linux/compiler-gcc4.h */  
  2. #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)  
  3.   
  4. /* linux-2.6.38.8/include/linux/stddef.h */  
  5. #undef offsetof  
  6. #ifdef __compiler_offsetof  
  7. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)  
  8. #else  
  9. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
  10. #endif  
  11.   
  12. #include <stdio.h>  
  13.   
  14. struct test_struct {  
  15.     int num;  
  16.     char ch;  
  17.     float fl;  
  18. };  
  19.   
  20. int main(void)  
  21. {  
  22.     printf("offsetof(struct test_struct, num) = %d\n",   
  23.             offsetof(struct test_struct, num));  
  24.       
  25.     printf("offsetof(struct test_struct,  ch) = %d\n",   
  26.             offsetof(struct test_struct, ch));  
  27.       
  28.     printf("offsetof(struct test_struct,  fl) = %d\n",   
  29.             offsetof(struct test_struct, fl));  
  30.       
  31.     return 0;  
  32. }  

    说明,__builtin_offsetof(a,b)是GCC的内置函数,可认为它的实现与((size_t) &((TYPE *)0)->MEMBER)这段代码是一致的。

    例子输出结果: 

[cpp] view plain copy
  1. offsetof(struct test_struct, num) = 0  
  2. offsetof(struct test_struct,  ch) = 4  
  3. offsetof(struct test_struct,  fl) = 8  

    其中代码难以理解的地方就是它灵活地运用了0地址。如果觉得&( (struct test_struct *)0 )->ch这样的代码不好理解,那么我们可以假设在0地址分配了一个结构体变量struct test_struct a,然后定义结构体指针变量p并指向a(struct test_struct *p = &a),如此我们就可以通过&p->ch获得成员ch的地址。由于a的首地址为0x0,所以成员ch的首地址为0x4。

 

    最后通过强制类型转换(size_t)把一个地址值转换为一个整数。

    分析完container_of的定义,接下来举两个例子来体会一下它的使用方法。

    正确的例子,如清单2: 

[cpp] view plain copy
  1. /* linux-2.6.38.8/include/linux/compiler-gcc4.h */  
  2. #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)  
  3.   
  4. /* linux-2.6.38.8/include/linux/stddef.h */  
  5. #undef offsetof  
  6. #ifdef __compiler_offsetof  
  7. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)  
  8. #else  
  9. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
  10. #endif  
  11.   
  12. /* linux-2.6.38.8/include/linux/kernel.h * 
  13.  * container_of - cast a member of a structure out to the containing structure 
  14.  * @ptr: the pointer to the member. 
  15.  * @type:   the type of the container struct this is embedded in. 
  16.  * @member:    the name of the member within the struct. 
  17.  * 
  18.  */  
  19. #define container_of(ptr, type, member) ({      \  
  20.     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \  
  21.     (type *)( (char *)__mptr - offsetof(type,member) );})  
  22.   
  23. #include <stdio.h>  
  24.   
  25. struct test_struct {  
  26.     int num;  
  27.     char ch;  
  28.     float fl;  
  29. };  
  30.   
  31. int main(void)  
  32. {  
  33.     struct test_struct init_test_struct = { 99, 'C', 59.12 };  
  34.   
  35.     char *char_ptr = &init_test_struct.ch;  
  36.   
  37.     struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);  
  38.       
  39.     printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",   
  40.         test_struct->num, test_struct->ch, test_struct->fl);  
  41.       
  42.     return 0;  
  43. }  

    例子输出结果: 

[cpp] view plain copy
  1. test_struct->num = 99  
  2. test_struct->ch = C  
  3. test_struct->fl = 59.119999  

    不适当的例子,如清单3: 

[cpp] view plain copy
  1. /* linux-2.6.38.8/include/linux/compiler-gcc4.h */  
  2. #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)  
  3.   
  4. /* linux-2.6.38.8/include/linux/stddef.h */  
  5. #undef offsetof  
  6. #ifdef __compiler_offsetof  
  7. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)  
  8. #else  
  9. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
  10. #endif  
  11.   
  12. /* linux-2.6.38.8/include/linux/kernel.h * 
  13.  * container_of - cast a member of a structure out to the containing structure 
  14.  * @ptr: the pointer to the member. 
  15.  * @type:   the type of the container struct this is embedded in. 
  16.  * @member:    the name of the member within the struct. 
  17.  * 
  18.  */  
  19. #define container_of(ptr, type, member) ({      \  
  20.     const typeof( ((type *)0)->member ) *__mptr = (ptr);    \  
  21.     (type *)( (char *)__mptr - offsetof(type,member) );})  
  22.   
  23. #include <stdio.h>  
  24.   
  25. struct test_struct {  
  26.     int num;  
  27.     char ch;  
  28.     float fl;  
  29. };  
  30.   
  31. int main(void)  
  32. {  
  33.     char real_ch = 'A';  
  34.     char *char_ptr = &real_ch;  
  35.   
  36.     struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);  
  37.   
  38.     printf(" char_ptr = %p  test_struct = %p\n\n", char_ptr, test_struct);  
  39.   
  40.     printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",   
  41.         test_struct->num, test_struct->ch, test_struct->fl);  
  42.       
  43.     return 0;  
  44. }  

    例子输出结果: 

[cpp] view plain copy
  1. char_ptr = 0xbfb72d7f  test_struct = 0xbfb72d7b  
  2.   
  3. test_struct->num = -1511000897  
  4. test_struct->ch = A  
  5. test_struct->fl = 0.000000  

    注意,由于这里并没有一个具体的结构体变量,所以成员num和fl的值是不确定的。

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

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

相关文章

mysql concat例子_MYSQL中CONCAT详解

concat()函数1. 功能&#xff1a;返回结果为连接参数产生的字符串。如有任何一个参数为NULL &#xff0c;则返回值为 NULL。2. 语法concat(str1, str2,...)3. 例子案例一&#xff1a;mysql> select concat(苹果,香蕉,梨子);------------------------------| CONCAT(苹果,香蕉…

常见的状态响应码

200&#xff1a;请求正常&#xff0c;服务器正常的返回数据 301&#xff1a;永久重定向。比如在访问www.jingdong.com的时候&#xff0c;会重定向到www.jd.com。 302&#xff1a;临时重定向。比如在访问一个需要登录的界面时&#xff0c;而此时没有登录&#xff0c;那么就会重定…

软件行业为什么那么多项目经理

记得听谁说过&#xff0c;软件行业的项目经理太滥了&#xff0c;二十几岁的毛头小伙子&#xff0c;动不动就是项目经理&#xff0c;手下没几个人&#xff0c;管的也没几个事&#xff0c;在其他行业&#xff0c;项目经理一般都是四五十岁的老头子做&#xff0c;要联系这&#xf…

ipv6的表示方法

v冒分十六进制表示法X:X:X:X:X:X:X:X 其中X表示地址中16位二进制数的十六进制值 例&#xff1a;FEDC:BA98:7654:3210:FEDC:BA98:7654:3210 v零压缩法如其中有多个连续的零&#xff0c;则可用零压缩法 如 &#xff1a;1080:0000:0000:0000:0008:0800:200C:417A 可写成&am…

mysql php7安装配置_centos7无网络下安装部署php7.1.33+mysql5.7.28+apache2.4.6-Go语言中文社区...

centos7无网络下安装部署php7.1.33mysql5.7.28apache2.4.6一、1、先ping www.baidu.com&#xff0c;root账户下&#xff0c;如果未联网&#xff0c;创建目录&#xff0c;把提前下载好的rpm包拷贝到rpm目录下如图&#xff1a;(如果没有安装包请查看我的另一篇教程下载这些安装包…

webkit渲染

2019独角兽企业重金招聘Python工程师标准>>> 参考链接 理解WebKit和Chromium 简明魔法学院 Chrome软件渲染 WebKit渲染基础 Webkit 渲染基础 Webkit不是浏览器,它是一个渲染引擎 软件渲染 硬件渲染(GPU加速) 会触发GPU加速的属性 CSS3 3D transformation, trans…

element ui中dialog相关问题

一&#xff0c;今天需要在dialog里面引入另一个页面&#xff0c;就是打开dialog显示该页面&#xff08;把页面放到dialog中&#xff09;&#xff0c;引入的语句如下&#xff1a; <iframe src"view?pathrkdj_b" ></iframe> 二&#xff0c;使用table组件时…

数据结构与算法--4.使用堆栈模拟队列

问题&#xff1a; 队列的插入和删除遵循先入先出的原则&#xff0c;而堆栈遵循后进先出的原则。用两个堆栈模拟队列&#xff0c;要求实现时不能分配超过O&#xff08;1&#xff09;的内存&#xff0c;时间复杂度必须是o&#xff08;m&#xff09;。 思路&#xff1a; 用两个…

IT行业的你,在成本部门还是利润部门

题外话&#xff1a;本文应该引起项目管理者和开发人员的思考&#xff1a;如何进行薪酬管理&#xff1f;如何规划职业生涯&#xff1f; 生在IT行业&#xff0c;发现周围很多朋友对薪酬问题有疑问&#xff0c;因为这种不解&#xff0c;导致经常带情绪&#xff0c;对工作、生活很…

ipv4到ipv6的过渡

v双协议站&#xff1a;过渡时期&#xff0c;站点必须同时支持IPv4和IPv6v隧道技术&#xff1a;IPv6主机之间通信必须使用IPv4的隧道v首部转换&#xff1a;用于发送方使用IPv6&#xff0c;而接收方使用IPv4

关于爬虫中常见的两个网页解析工具的分析 —— lxml / xpath 与 bs4 / BeautifulSoup...

http://www.cnblogs.com/binye-typing/p/6656595.html 读者可能会奇怪我标题怎么理成这个鬼样子&#xff0c;主要是单单写 lxml 与 bs4 这两个 py 模块名可能并不能一下引起大众的注意&#xff0c;一般讲到网页解析技术&#xff0c;提到的关键词更多的是 BeautifulSoup 和 xpat…

java如何去掉html标签_Java后端去掉HTML标签获取纯文本-Fun言

今天又对我的博客首页进行了一次版本的更新&#xff0c;使其自适应屏幕&#xff0c;获得更好的用户体验&#xff0c;然后就出现点小问题&#xff0c;那就是原来的摘要是人为添加的&#xff0c;有长有短&#xff0c;对自适应屏幕有影响&#xff0c;所以我们现在是截取文章的前20…

单/双中括号与测试条件

测试命令 tesst[]内置命令[[]]bash中的关键字 单中括号 格式[#express1#op#express2#] 注意&#xff1a;   其中#代表括号不能省略   不能匹配模式   变量引用应用双引号括起&#xff0c;尤其当变量引用有空格时   与或非形式-a –o -not   常量应用单/双引号括起  …

暗时间--平凡与优秀间的距离

每个人都希望&#xff0c;在他所从事的领域很优秀&#xff0c;那么如何才能优秀呢&#xff1f;有人做过一个研究&#xff0c;说那些优秀的音乐家&#xff0c;在他们成名之前&#xff0c;已经训练过10000小时。有人可能成功得早&#xff0c;如莫扎特16岁&#xff0c;有些可能需要…

IP分组

IP分组就是根据Ip地址来进行分组&#xff0c;目的可以是为了对不同 的地址组分配不同的带宽&#xff08;限速&#xff09;配置地址组时&#xff0c;其输入格式为A.B.C.D-A.B.C.E&#xff0c;例如&#xff1a;192.168.1.1-192.168.1.250

python3基础3--数据类型--数据运算--表达式if -else-while-for

一、python3 数据类型 1.1 数字例如&#xff1a;1,2,3,4等1.2 int&#xff08;整型&#xff09; 在32位机器上&#xff0c;整数的位数为32位&#xff0c;取值范围为-2**31&#xff5e;2**31-1&#xff0c;即-2147483648&#xff5e;2147483647在64位系统上&#xff0c;整数的位…

spark java教程_(Spark)学习进度十四(Spark之Java独立应用编程)

环境如下:(更新了林子雨教程中不可使用的部分) Hadoop 2.6.0以上 java JDK 1.7以上 Spark 3.0.0-preview2 二、java独立应用编程(在下载依赖jar包的过程中如遇到卡顿现象可以Ctrl+C停止下载,然后重新执行本条命令即可继续下载相应的依赖jar包) 1、安装maven ubuntu中没有自带…

nowcoderD Xieldy And His Password

题意:一个01序列,长度1e6,问有多少子串十进制是3的倍数 题解:DP[i][j]代表前i个并且以i为结尾,且十进制%3j的串的个数 #include<bits/stdc.h> #define maxn 1001000 using namespace std; char s[maxn]; long long dp[maxn][3], sum; int main(){while(~scanf("%s&q…

3D电视,你知道多少?

1.3D电视常见知识 系统概述篇 1、 什么是3D电视&#xff1f; 答&#xff1a;3D电视是一种能够模拟实际景物的真实空间关系的新型电视&#xff0c;它利用人眼的视觉特性产生立体感&#xff0c;让观众感受到观看的影像是具有深度特性的三维立体场景&#xff0c;观众对延伸于屏幕…

testng.xml文件配置

TestNG的DTD检查文件&#xff1a;http://testng.org/testng-1.0.dtd.php <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <!--suite&#xff08;测试套件&#xff09;为根…