linux中 list_entry 设计背景及原理解析

这篇具有很好参考价值的文章主要介绍了linux中 list_entry 设计背景及原理解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux 2.4.22

在这一版本中的 list_entry的宏定义实现如下:

#define list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

乍一看,会觉得特别复杂,其实分析之后,会发现清晰明了:

实现背景:

linux 中 list 为了实现类似 c++ list模板的效果,即一个list可以适用于各种不同的struct。便采用类似下图的设计,使list 相当于一个绳索,可以挂载各种 struct。通过当前 list_head可以得到所挂载的struct指针,便实现了类似于模板效果。
如下实例

typedef struct page {
	struct list_head list;
	struct address_space *mapping;
	unsigned long index;
    ...
};
page = list_entry(curr, struct page, list);

linux中 list_entry 设计背景及原理解析

原理

实现通过当前 list_head得到所挂载的struct指针,便是借助于 list_entry。

#define list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
  1. (unsigned long)(&((type *)0)->member) 用于算出 member 相对于 struct 的 offset。
    因为C语言中可以对地址进行强制类型转换,不管这个地址的原始类型,也不管是否合法。这里首先对地址 0 进行强制类型转换,然后取变量member的地址。因为起始地址为0,这里的member的绝对地址等价于相对地址。类似的等价实现如下:
#define offsetof(type,field)	((char *) &((type *) 0)->field - (char *) 0)
  1. ((type *)((char *)(ptr)- offset)) ptr 减去 offset 即可得到原始指针的位置。

最新实现

但是在新的C语言规范中,对地址 0 进行强转会出现未定义行为,取而代之的是适用编译器实现的__builtin_offsetof

最新的linux source code 实现如下:

#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

#define container_of(ptr, type, member) ({				\
	void *__mptr = (void *)(ptr);					\
	static_assert(__same_type(*(ptr), ((type *)0)->member) ||	\
		      __same_type(*(ptr), void),			\
		      "pointer type mismatch in container_of()");	\
	((type *)(__mptr - offsetof(type, member))); })

#define offsetof(TYPE, MEMBER)	__builtin_offsetof(TYPE, MEMBER)

可以发现在最新的linux source code 中,list_entry 计算偏移的方式变为了__builtin_offsetof。

参考:文章来源地址https://www.toymoban.com/news/detail-455825.html

  • offsetof
  • Does &((struct name *)NULL -> b) cause undefined behaviour in C11?

到了这里,关于linux中 list_entry 设计背景及原理解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • list_for_each_entry详解

    参考链接: 终于理解list_entry和list_for_each_entry linux 内核代码中list_for_each_entry宏之我见 linux之list_for_each和list_for_each_entry函数 container_of的用法 用户态下的list.h Linux内核中的许多链表操作,都是使用list_for_each_entry进行遍历,其定义在/usr/src/linux-2.6.32.9/include/linux/list.h路径,具体

    2024年02月15日
    浏览(38)
  • 更快更准 | YOLOv3算法超详细解析(包括诞生背景+论文解析+技术原理等)

    前言: Hello大家好,我是小哥谈。 YOLOv3是一种基于深度学习的目标检测算法,它可以快速而准确地在图像中检测出多个目标。它是由Joseph Redmon和Ali Farhadi在2018年提出的,是YOLO(You Only Look Once)系列算法的第三个版本。YOLOv3算法使用了Darknet-53网络作为其主干网络,并且采用了

    2024年01月20日
    浏览(40)
  • 系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第八部分:Linux、安全

    本心、输入输出、结果 编辑:简简单单 Online zuozuo 地址:https://blog.csdn.net/qq_15071263 如果觉得本文对你有帮助,欢迎点赞、收藏、评论 我们使用视觉效果和简单术语来解释复杂的系统是如何运转的,帮助我们理解技术细节 我们使用视觉效果和简单术语来解释复杂的系统是如何

    2024年02月03日
    浏览(36)
  • 【Linux】Linux背景&&常见的基本指令

    Linux是一种自由和开放源代码的类UNIX操作系统,该操作系统的内核由 林纳斯托瓦兹 在1991年首次发布,之后,在加上用户空间的应用程序之后,就成为了Linux操作系统。严格来讲,Linux只是操作系统内核本身,但通常采用“Linux内核”来表达该意思。而Linux则常用来指基于Linu

    2023年04月19日
    浏览(33)
  • 【Linux 系统编程】Linux背景介绍 及 基本指令详解(一)

    1.1 发展史 本门课程学习Linux系统编程,你可能要问Linux从哪里来?它是怎么发展的?在这里简要介绍Linux的发展史。要说Linux,还得从UNIX说起。 UNIX发展的历史 1968年,一些来自通用电器公司、贝尔实验室和麻省理工学院的研究人员开发了一个名叫Multics的特殊操作系统。Multi

    2024年02月11日
    浏览(45)
  • Linux历史背景和环境

    世界上第一台ENIAC计算机诞生于美国宾夕法尼亚大学(1946.2.14),此计算机的目的是为了计算导弹的弹道,研究出来给军方使用的,重量足足有30吨,当时的计算机只能顶尖的实验室人员才能使用。 1969年才有了 世界上第一个操作系统UNIX ,用 C语言编写的UNIX操作系统 ,由 贝

    2024年02月04日
    浏览(38)
  • 【Linux】相关背景及环境搭建

    前言: 认识 Linux, 了解 Linux 的相关背景,学会如何使用云服务器,掌握使用远程终端工具 xshell 登陆 Linux 服务器 Linux 是一种开源的类 UNIX 操作系统内核,最早由芬兰的林纳斯·托瓦兹(Linus Torvalds)在1991年创建。而UNIX 是一种多用户、多任务操作系统,是操作系统领域的经典

    2024年01月22日
    浏览(38)
  • 【初识Linux】:背景介绍以及环境搭建

    朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux的基础知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏: C语言:从入门到精通 数据结构专栏: 数据结构 个  人  主  页 : stackY、 目录 1. Linux背景介绍    

    2024年02月06日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包