我是靠谱客的博主 敏感煎蛋,最近开发中收集的这篇文章主要介绍linux 内核链表遍历宏 list_for_each_entry list_for_each_entry_safe,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

看内核代码都会发现,内核链表的操作常用的二个宏list_for_each_entry和list_for_each_entry_safe
循序渐进,先从最底层的函数container_of 函数说起,其内核定义如下:

先看offsetof宏,根据优先级的顺序,最里面的小括号优先级最高,

TYPE *将整型常量0强制转换为TYPE型的指针,且这个指针指向的地址为0,

也就是将地址0开始的一块存储空间映射为TYPE型的对象,

接下来再对结构体中MEMBER成员进行取址,而整个TYPE结构体的首地址是0,

这里获得的地址就是MEMBER成员在TYPE中的相对偏移量。

再将这个偏移量强制转换成size_t型数据(无符号整型)。

所以整个offsetof的功能就是获取MEMBER成员在TYPE型数据中的偏移量

再看看container_of宏,他首先赋值member成员的指针给__mptr,

然后减去成员在结构体中的相对偏移量,

这样就可以获得对应的结构体的(地址)指针;

从注释可以看出,他的作用是获取结构体实体指针,他其实就是container_of
进入主题来看list_for_each_entry,宏定义如下所示:

首先需要了解双向链表和链表头的概念:建立一个双向链表通常有一个独立的用于管理链表的链表头,链表头一般是不含有实体数据的,必须用INIT_LIST_HEAD()进行初始化,表头建立以后,就可以将带有数据结构的实体链表成员加入到链表中;链表头和链表的示意如下:


 
list_for_each_entry宏是一个for循环语句,

for循环的第一个参数就是让(head)->next指向member成员所在数据结构的指针,

也就是将pos初始化为链表头指向的第一个实体链表成员,

for的第三句话通过pos->member.next指针遍历整个实体链表,

当pos->member.next再次指向我们的链表头的时候跳出for循环。

整个过程没有对链表头进行遍历(不需要被遍历),

所以使用list_for_each_entry遍历链表必须从链表头开始。

因此可以看出,list_for_each_entry的功能就是遍历以head为链表头的实体链表,对实体链表中的数据结构进行处理;

相比于list_for_each_entry,list_for_each_entry_safe用指针n对链表的下一个数据结构进行了临时存储,

所以如果在遍历链表的时候需要做删除链表中的当前项操作时,

用list_for_each_entry_safe可以安全的删除,而不会影响接下来的遍历过程(用n指针可以继续完成接下来的遍历,

list_for_each_entry则无法继续遍历,删除后会导致无法继续遍历)。

 

 

最后

以上就是敏感煎蛋为你收集整理的linux 内核链表遍历宏 list_for_each_entry list_for_each_entry_safe的全部内容,希望文章能够帮你解决linux 内核链表遍历宏 list_for_each_entry list_for_each_entry_safe所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部