首先来个简单版本

 /* given a pointer @ptr to the field @member embedded into type (usually
* struct) @type, return pointer to the embedding instance of @type. */
#define container_of(ptr, type, member) \
((type *)((char *)(ptr)-(char *)(&((type *))->member)))

  作用:主要用于结构体,给定一个指针ptr指向一个结构体type的实例的成员member,返回此结构体实例的首地址,也就是这个结构体实例的指针,啰嗦一堆,还不如一个实例:

 typedef struct ABC{
char a;
char b;
int c;
}ABC; int main(int argc, const char *argv[])
{
ABC ins; printf("%p\n", container_of(&ins.c, ABC, c));
printf("%p\n", &ins);
return ;
}

  打印出来的值应该是相等的,都是结构体ins的首地址。我们将宏展开:

 container_of(&ins.c, ABC, c);
//展开后
((ABC *)((char *)(&ins.c)-(char *)(&((ABC *))->c)));

  在减号的2边分别是2个部分,前面: (char *)(&ins.c),也就是指向ins的成员c的指针,后面:(char *)( &(((ABC *)0)->c))就是成员c相对于结构体ABC指针的偏移,比如在本例中:

成员c的指针(&ins.c)减去成员c的偏移(offset)那么得到的就是结构体ins首地址。如果我只知道某个结构体成员的指针值,那么通过container_of宏就可以得到结构体指针,那么就可以随意访问它的任意一个成员。

升级版:

 #define offsetof(typ,memb) ((long)(long_ptr_t)((char *)&(((typ *)0)->memb)))
#define container_of(ptr, type, member) ({ \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

升级版有何改进呢?我就我知道的总结下:

1.const修饰,确保传入的ptr指向不被修改。2.使用了一个中间变量,定义一个成员member类型的变量指针__mptr,然后将ptr赋值给它。为何要这样?就是为了以防万一,如果你搞错了传的指针不是指向成员member的,那么编译器至少会有个警告。

3.offset宏使用(long)(long_ptr_t)2个数据类型作强转我没看太懂,(long long )64位?一个成员的偏移有可能超过32位?倒是__mptr这个地址值可能超过32位(寻址超过4G)。不解。

参考:

  http://broken.build/2012/11/10/magical-container_of-macro/

  linux 3.13.0内核。

linux内核宏container_of的更多相关文章

  1. linux内核宏container_of前期准备之gcc扩展关键字typeof

    typeof基本介绍 typeof(x) 这是它的使用方法,x可以是数据类型或者表达式.它的作用时期和sizeof类似,就是它是在编译器从高级语言(如C语言)翻译成汇编语言时起作用,这个很重要,稍后会 ...

  2. Linux内核中container_of宏的详细解释

    上一节拒绝造轮子!如何移植并使用Linux内核的通用链表(附完整代码实现)我们在分析Linux内核链表的时候注意到内核在求解结构体偏移的时候巧妙的使用了container_of宏定义,今天我们来详细剖 ...

  3. Linux内核宏DEVICE_ATTR使用

    1.前言 在Linux驱动程序编写中,使用DEVICE_ATTR宏,可以定义一个struct device_attribute设备属性,并使用sysfs的API函数,便可以在设备目录下创建出属性文件, ...

  4. linux内核代码container_of

    它的作用显而易见,那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针. typedef unsigned int __kernel_size_t; typedef __ke ...

  5. Linux内核中container_of函数详解

    http://www.linuxidc.com/Linux/2016-08/134481.htm

  6. linux内核中链表代码分析---list.h头文件分析(一)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637596.html linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17 ...

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

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

  8. Linux内核中的常用宏container_of

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

  9. 嵌入式C语言自我修养 04:Linux 内核第一宏:container_of

    4.1 typeof 关键字 ANSI C 定义了 sizeof 关键字,用来获取一个变量或数据类型在内存中所占的存储字节数.GNU C 扩展了一个关键字 typeof,用来获取一个变量或表达式的类型 ...

随机推荐

  1. 以对象的方式来访问xml数据表(二)

    为什么要以对象的方式来访问xml数据表? 还记得,自己是在一次完成师兄布置的任务时接触到了xml,那时候需要用xml来作为数据文件,保存一个简单的图书管理系统的数据.于是就知道了,可以用xml文件来保 ...

  2. 关于领域驱动设计(DDD)仓储的思考

    为什么需要仓储呢?领域对象(一般是聚合根)的被创建出来后的到最后持久化到数据库都需要跟数据库打交道,这样我们就需要一个类似数据库访问层的东西来管理领域对象.那是不是我们就可以设计一个类似DAL层的东东 ...

  3. winform(容器、打印、对话框)

    一.布局:2个属性:Anchor:锁定位置Dock:填充位置一般Dock是与容器控件配合使用 二.容器控件:Panel:就是一个区域,类似于DIV,可以独立布局,还可以让其它控件及容器在它的内部再次布 ...

  4. CentOS安装Erlang

    1.首先要安装编译源码用的编译器gcc&g++,安装方式很简单,先用yum search gcc搜索出包,然后选择适合自己的版本复制全名,用yum intall gcc_XXX来进行安装即可. ...

  5. 美丽的阴影(剖析jquery主页)

    jquery Download API Documentation Blog Plugins Browser Support jquery主页第一眼看到的就是这个玻璃渣效果,设计者利用高光和阴影制造出 ...

  6. css3属性(一)

    圆角效果: border-radius: 5px 4px 3px 2px; /* 四个半径值分别是左上角.右上角.右下角和左下角,顺时针 */ 阴影: box-shadow:X轴偏移量 Y轴偏移量 [ ...

  7. JavaScript中instanceof运算符的用法以及和typeof的区别

    instanceof : 判断一个对象是否为某一数据类型,或一个变量是否为一个对象的实例:返回boolean类型栗子①: var aColors = ["red", "g ...

  8. ABAP 表格控制(Table Control)和步循环

    表格控制(Table Control)和步循环     1.两个标准Demo: SAPMTZ60,SAPMTZ61 2.简介 3.建立Table Control程序的基本流程 4.使用步循环 5.表格 ...

  9. 网站SEO之百度优化不得不知的铁人三项规则

    奥运会有铁人三项,此运动更好的协调了运动员的综合素质水平,而百度优化排名中的“铁人三项”规则则是让网站的整体质量更好的满足市场用户体验.针对不同部分的操作,可以让网站在每个细节处都能凸显以人为本的服务 ...

  10. Java解析XML三种常用方法

    1.使用DOM方式解析: package com.wzh.dom; import java.util.Iterator; import javax.xml.parsers.DocumentBuilde ...