我是靠谱客的博主 迷路大雁,最近开发中收集的这篇文章主要介绍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则无法继续遍历,删除后会导致无法继续遍历)。
 
参考文献:http://www.zhimengzhe.com/linux/75966.html
        https://blog.csdn.net/u013904227/article/details/50931540

最后

以上就是迷路大雁为你收集整理的list_for_each_entry和list_for_each_entry_safe的全部内容,希望文章能够帮你解决list_for_each_entry和list_for_each_entry_safe所遇到的程序开发问题。

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

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

评论列表共有 0 条评论

立即
投稿
返回
顶部