在Linux内核源码中,实现和链表相关的接口list_entry()时,会调用container_of()宏定义,它的作用是:给定结构体中某个成员的地址、该结构体类型和该成员的名字获取这个成员所在的结构体变量的首地址。有点绕,没关系,接着往下看就能明白了。
container_of()宏定义实现如下所示

/*** 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) );})

要看懂上述代码,需要知道三个关键点:

  1. typeof(),取变量或表达式类型,可参考之前typeof的文章
  2. typeof( ((type *)0)->member ),用typeof( ((struct apple *)0)->color ) 解释更易理解,它的作用是获取结构体apple中变量color的类型,可参考之前的文章
  3. offsetof(),获取结构体中某个成员相对于该结构体首元素地址的偏移量

好了,再开始解释container_of(),其三个入参含义:

  1. ptr:结构体变量中某个成员的地址
  2. type:结构体类型
  3. member:该结构体变量的具体名字

比如如下结构体struct ipstore,假设已经有一个变量struct ipstore *ist1;,并给ist1分配好了内存且进行了初始化,在已知结构体成员list的地址的情况下,获取list所在的结构体变量ist1的首地址。此时有人就会问了,这里ist1明明是已知的,这么做不是自己给自己找麻烦吗?这是个好问题,但是不要忘记,本文到目前为止只是讲解container_of()的含义,并没有说它适合用在什么样的场景下,因为有一种使用场景,当链表是通过list串起来的时候,此时并不知道ist1的首地址,反而是知道list的地址,这时container_of()就非常合适了,内核中的链表就是这么做的。

struct list_head {struct list_head *next;struct list_head  *prev;
};struct ipstore{unsigned long time;__u32 addr[4];struct list_head list;
};

所以,调用container_of()时具体的传参如下所示,其返回的结果是ist1的地址。

container_of(ist1->list, struct ipstore, list)

如下测试代码,通过container_of()取得了ip1的地址。

void container_of_test()
{struct ipstore ip1;struct ipstore *p1;p1 = container_of(&ip1.list, struct ipstore, list);printf("ip1's addr:0x%0x\n", &ip1);printf("p1's  addr:0x%0x\n", p1);
}
[root@xxx c_base]# ./a.out
ip1's addr:0xa5fe1fe0
p1's  addr:0xa5fe1fe0

C语言高级用法---container_of()相关推荐

  1. 【嵌入式】C语言高级编程-container_of宏(04)

    00. 目录 文章目录 00. 目录 01. typeof 关键字 02. typeof与宏结合 03. typeof在内核源码中应用 04. container_of 宏分析 05. contain ...

  2. C语言高级用法---typeof()关键字

    前言 typeof() 是GUN C提供的一种特性,可参考C-Extensions,它可以取得变量的类型,或者表达式的类型. 本文总结了typeof()关键字的常见用法,并给出了相应的例子,以加深理解 ...

  3. C语言 —— 你不得不知道的 scanf 的高级用法

    如果你想让自己的输入更加炫酷.更加个性化.更加安全,那么还需要学习 scanf() 的高级用法,这才是大神和菜鸟的分水岭. 好了,言归正传,我们分三个方面讲解 scanf() 的高级用法. 1) 指定 ...

  4. Linux基础和c语言的高级用法

    Linux基础 基础命令 与文件相关的: mkdir:创建一个目录文件 touch:创建一个普通文件 rmdir:删除一个空的目录文件 cd:+目录名:进入该目录文件 +路径:进入该路径下 ls:显示 ...

  5. 合并多个结果集 SQL语言的高级用法

    GPS平台.网站建设.软件开发.系统运维,找森大网络科技! https://cnsendnet.taobao.com 来自森大科技官方博客 http://www.cnsendblog.com/inde ...

  6. Python进阶:切片的误区与高级用法

    众所周知,我们可以通过索引值(或称下标)来查找序列类型(如字符串.列表.元组...)中的单个元素,那么,如果要获取一个索引区间的元素该怎么办呢? 切片(slice)就是一种截取索引片段的技术,借助切片 ...

  7. php switch case 判断语句,PHP的switch判断语句的“高级”用法详解,switch详解_PHP教程...

    PHP的switch判断语句的"高级"用法详解,switch详解 只所以称为"高级"用法,是因为我连switch的最基础的用法都还没有掌握,so,接下来讲的其实 ...

  8. SAP UI5 应用开发教程之六十 - SAP UI5 地图控件的一些高级用法试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  9. PHP使用Switch语句判断星座,PHP的switch判断语句的“高级”用法详解 用switch语句怎样判断成绩的等级...

    php switch case 求具体详解,case里面能加if语句? swich 语句 我非常喜欢用 case里面加if干嘛 . php switch中能加if语句吗 PHP里 switch cas ...

最新文章

  1. “我,懂数据,不怕被裁”:这项核心能力到底有多香?
  2. centos7安装postgresql数据库
  3. POJ 2749 Building roads
  4. IT 巡检内容、工具、方法 amp; Linux / AIX / Oracle / VMware 巡检表模板 | 周末送资料...
  5. 【CyberSecurityLearning 2】IP地址与DOS命令
  6. xampp mysql登录失败_XAMPP修改mysql的root密码phpmyadmin无法登陆
  7. Excel有用的函数(ISBLANK,IF,LEFT,VALUE)
  8. 2.5 矩阵乘法规则
  9. [css] 请说说颜色中#F00的每一位分别表示什么?为什么会有三位和六位的表示呢?
  10. Meanshift 均值飘移实现图像聚类 MATLAB实现(4)
  11. 为什么我的mysql比redis快_为什么redis是单线程的以及为什么这么快?
  12. 中国联通联合中国电信在福建开通首个共享5G基站
  13. android 多线程类,Android 多线程处理之多线程用法大集合
  14. 1个开发如何撑起一个过亿用户的小程序
  15. Python爬虫之模拟CSDN网站登录
  16. nrf24l01无线模块c语言程序,NRF24L01 无线通信模块使用
  17. linux 设置unix格式化,linux格式化
  18. 远景html制造机模板,台式机ALC892制作仿冒appleHDA的教程,前置MIC自动检测。
  19. mysql/hive求实际活动时间
  20. speedpdf——PDF转PPT免费在线转换还不限制页数哦

热门文章

  1. php官方微信接口大全(微信支付、微信红包、微信摇一摇、微信小店)
  2. 佐治亚大学计算机博士,美国佐治亚大学,光电专业,全奖博士招生
  3. Matlab时频工具箱tftb-0.2安装
  4. 【嵌入式系统—实时操作系统】uC/OS II源码的官网下载
  5. 数学之美—细数 傅里叶变换 原理
  6. 美术基础对学3D游戏建模重要吗?零基础如何学3D建模
  7. 用fail2ban阻止ssh暴力破解root密码
  8. 优雅地从浏览器打开本地应用
  9. Mac—删除默认英文输入法
  10. c++一本通 1238一元三次方程求解