转自: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的定义如下:

  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:

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

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

例子输出结果:

  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:

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

例子输出结果:

  1. test_struct->num = 99
  2. test_struct->ch = C
  3. test_struct->fl = 59.119999

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

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

例子输出结果:

  1. char_ptr = 0xbfb72d7f  test_struct = 0xbfb72d7b
  2. test_struct->num = -1511000897
  3. test_struct->ch = A
  4. test_struct->fl = 0.000000

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

Linux内核中的常用宏container_of其实很简单【转】的更多相关文章

  1. Linux内核中的常用宏container_of其实很简单

    http://blog.csdn.net/npy_lp/article/details/7010752 通过一个结构体变量的地址,求该结构体的首地址. #ifndef CONTAINER_OF #de ...

  2. (十)Linux内核中的常用宏container_of

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

  3. Linux内核中的常用宏container_of

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

  4. 《C预处理》Linux内核中可变参数宏的用法

    http://blog.csdn.net/tankai19880619/article/details/12015305

  5. linux内核中的宏ffs(x)

    linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在 arch/arm/include/asm/bitops.h #define ffs(x) ({ unsigned long __ ...

  6. Linux内核中双向链表的经典实现

    概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核 ...

  7. Linux 内核中的 GCC 特性

    https://www.ibm.com/developerworks/cn/linux/l-gcc-hacks/ GCC 和 Linux 是出色的组合.尽管它们是独立的软件,但是 Linux 完全依靠 ...

  8. 剖析linux内核中的宏---------container_of

    #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...

  9. Linux内核中常用的数据结构和算法(转)

    知乎链接:https://zhuanlan.zhihu.com/p/58087261 Linux内核代码中广泛使用了数据结构和算法,其中最常用的两个是链表和红黑树. 链表 Linux内核代码大量使用了 ...

随机推荐

  1. SQL中 ALL 和 ANY 区别的

    在select中我们可能会认为all和any应该表达的意思差不多.其实他们的意思完全不一样: all: 是将后面的内容看成一个整体,如: >all (select age from studen ...

  2. [六]SpringBoot 之 连接数据库(mybatis)

    在进行配置之前首先要了解springboot是如何使用纯java代码方式初始化一个bean的 以前的版本是在xml中使用beans标签,在其里面配置bean,那么纯Java代码怎么实现呢? 答案就是使 ...

  3. 【BZOJ2109/2535】【NOI2010】航空管制(贪心)

    [BZOJ2109/2535][NOI2010]航空管制(贪心) 题面 BZOJ2109 BZOJ2535 题解 很好玩的一道题目 先看第一问,显然是要找一个合法的拓扑排序的序列. 直接拓扑排序,把队 ...

  4. Hbase(二)hbase建表

    一.建表高级属性 下面几个 shell 命令在 hbase 操作中可以起到很到的作用,且主要体现在建表的过程中,看 下面几个 create 属性 1.bloomfilter 布隆过滤器 默认是 NON ...

  5. 2656: [Zjoi2012]数列(sequence)(递归+高精度)

    好久没写题了T T NOIP 期中考双血崩 显然f(x)=f(x>>1)+f((x>>1)+1),考虑每次往x>>1递归,求出f(x),复杂度O(logN) 我们设 ...

  6. PID控制算法的C语言实现三 位置型PID的C语言实现

    上一节中已经抽象出了位置性PID和增量型PID的数学表达式,这一节,重点讲解C语言代码的实现过程,算法的C语言实现过程具有一般性,通过PID算法的C语言实现,可以以此类推,设计其它算法的C语言实现. ...

  7. laravel5.1 关联模型保存的方法(使用associate方法)

    模型定义 class User { public function customer() { return $this->hasOne('Customer'); } } class Custom ...

  8. 【转】解决virt-manager启动管理器出错:unsupported format character

    来源:http://blog.csdn.net/z_yttt/article/details/71192144 经验证OK.   今天打开virt-manager出错,报错信息如下: 启动管理器出错: ...

  9. Python基础之面向对象(进阶篇)

    面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 对象,根据模板创建的实例(即:对象),实 ...

  10. [DeeplearningAI笔记]序列模型3.1基本的 Seq2Seq /image to Seq

    5.3序列模型与注意力机制 觉得有用的话,欢迎一起讨论相互学习~Follow Me 3.1基础模型 [1] Sutskever I, Vinyals O, Le Q V. Sequence to Se ...