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的定义如下:
- #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的值。
第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。
其中的语法难点就是如何得出成员相对结构体的偏移量?
通过例子说明,如清单1:
- /* linux-2.6.38.8/include/linux/compiler-gcc4.h */
- #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
- /* linux-2.6.38.8/include/linux/stddef.h */
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- #include <stdio.h>
- struct test_struct {
- int num;
- char ch;
- float fl;
- };
- int main(void)
- {
- printf("offsetof(struct test_struct, num) = %d\n",
- offsetof(struct test_struct, num));
- printf("offsetof(struct test_struct, ch) = %d\n",
- offsetof(struct test_struct, ch));
- printf("offsetof(struct test_struct, fl) = %d\n",
- offsetof(struct test_struct, fl));
- return 0;
- }
说明,__builtin_offsetof(a,b)是GCC的内置函数,可认为它的实现与((size_t) &((TYPE *)0)->MEMBER)这段代码是一致的。
例子输出结果:
- offsetof(struct test_struct, num) = 0
- offsetof(struct test_struct, ch) = 4
- 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:
- /* linux-2.6.38.8/include/linux/compiler-gcc4.h */
- #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
- /* linux-2.6.38.8/include/linux/stddef.h */
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- /* linux-2.6.38.8/include/linux/kernel.h *
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
- #include <stdio.h>
- struct test_struct {
- int num;
- char ch;
- float fl;
- };
- int main(void)
- {
- struct test_struct init_test_struct = { 99, 'C', 59.12 };
- char *char_ptr = &init_test_struct.ch;
- struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);
- printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",
- test_struct->num, test_struct->ch, test_struct->fl);
- return 0;
- }
例子输出结果:
- test_struct->num = 99
- test_struct->ch = C
- test_struct->fl = 59.119999
不适当的例子,如清单3:
- /* linux-2.6.38.8/include/linux/compiler-gcc4.h */
- #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
- /* linux-2.6.38.8/include/linux/stddef.h */
- #undef offsetof
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
- /* linux-2.6.38.8/include/linux/kernel.h *
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
- #include <stdio.h>
- struct test_struct {
- int num;
- char ch;
- float fl;
- };
- int main(void)
- {
- char real_ch = 'A';
- char *char_ptr = &real_ch;
- struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);
- printf(" char_ptr = %p test_struct = %p\n\n", char_ptr, test_struct);
- printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",
- test_struct->num, test_struct->ch, test_struct->fl);
- return 0;
- }
例子输出结果:
- char_ptr = 0xbfb72d7f test_struct = 0xbfb72d7b
- test_struct->num = -1511000897
- test_struct->ch = A
- test_struct->fl = 0.000000
注意,由于这里并没有一个具体的结构体变量,所以成员num和fl的值是不确定的。
Linux内核中的常用宏container_of其实很简单【转】的更多相关文章
- Linux内核中的常用宏container_of其实很简单
http://blog.csdn.net/npy_lp/article/details/7010752 通过一个结构体变量的地址,求该结构体的首地址. #ifndef CONTAINER_OF #de ...
- (十)Linux内核中的常用宏container_of
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...
- Linux内核中的常用宏container_of
Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...
- 《C预处理》Linux内核中可变参数宏的用法
http://blog.csdn.net/tankai19880619/article/details/12015305
- linux内核中的宏ffs(x)
linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __ ...
- Linux内核中双向链表的经典实现
概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核 ...
- Linux 内核中的 GCC 特性
https://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/ GCC 和 Linux 是出色的组合.尽管它们是独立的软件,但是 Linux 完全依靠 ...
- 剖析linux内核中的宏---------container_of
#define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...
- Linux内核中常用的数据结构和算法(转)
知乎链接:https://zhuanlan.zhihu.com/p/58087261 Linux内核代码中广泛使用了数据结构和算法,其中最常用的两个是链表和红黑树. 链表 Linux内核代码大量使用了 ...
随机推荐
- LoadRunner脚本增强技巧之自动关联
为什么要做关联,原理很简单,录制脚本的时候,服务器会给用户一个唯一的认证码来进行操作,当再次回放脚本的时候服务器又会给一个全新的认证码,而录制好的脚本是写死的,还是拿老的认证码提交,肯定会导致脚本执行 ...
- BZOJ4899 记忆的轮廓(概率期望+动态规划+决策单调性)
容易发现跟树没什么关系,可以预处理出每个点若走向分叉点期望走多少步才能回到上个存档点,就变为链上问题了.考虑dp,显然有f[i][j]表示在i~n中设置了j个存档点,其中i设置存档点的最优期望步数.转 ...
- Python下json中文乱码解决办法
json.dumps在默认情况下,对于非ascii字符生成的是相对应的字符编码,而非原始字符,只需要 #coding=utf8 import json js = json.loads('{" ...
- WIN7 右下角音量图标不见了
1.呼叫出 任务管理器,结束掉 explorer.exe 进程 2.新建任务,浏览,找到 C:/windows/system32/systray.exe,确定加载 3.新建任务,输入explorer ...
- 【noip2018】【luogu5024】保卫王国
题目描述 Z 国有nn座城市,n - 1n−1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需要满足如下几个条 ...
- 复习JavaScript随手记
数据类型 基本类型 string number boolean undefined number类型,包含整数浮点数 NaN和自己都不相等,涉及NaN的计算结果都是NaN isNaN()函数用于判断一 ...
- Drivers Dissatisfaction 最小生成树+LCA
题意:给一张n个点m条边的连通图,每条边(ai,bi)有一个权值wi和费用ci, 表示这条边每降低1的权值需要ci的花费.现在一共有S费用可以用来降低某些边的权值 (可以降到负数),求图中的一棵权值和 ...
- Codeforces 830B - Cards Sorting 树状数组
B. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- vim 单文件中查找方法
1.vim 单文件中查找方法 正常模式下使用 / 或 ? 命令执行向后搜索或向前搜索 /love 从光标位置向前搜索关键词 love ?love 从光标位置向后搜索关键词 love 正常模式下 ...
- 一元回归_ols参数解读(推荐AAA)
sklearn实战-乳腺癌细胞数据挖掘(博客主亲自录制视频教程) https://study.163.com/course/introduction.htm?courseId=1005269003&a ...