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

概述

#define list_for_each_entry(pos, head, member)				
	for (pos = list_entry((head)->next, typeof(*pos), member);	
	     &pos->member != (head); 	
	     pos = list_entry(pos->member.next, typeof(*pos), member))

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

#define container_of(ptr, type, member) ({			
	const typeof(((type *)0)->member) * __mptr = (ptr);	    
	(type *)((char *)__mptr - offsetof(type, member)); })


#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

以上是从内核中得到的list_for_each_entry宏定义,下面依次分析它们。

 

1、typeof

功能:获取某一变量或表达式类型 (C99关键字)

 

(1)获取变量类型

         typeof(int*) == int *

 

(2)函数int max()

         typeof(max()) == int,且max函数不会执行,typeof只是获取返回类型

 

(3)const typeof( ((type *)0)->member ) *__mptr = (ptr);

         获取member在type类型结构体中的类型

 

(4)交换@a和@b数值

         存在严格的类型检测

#define swap(a, b) 

    do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)

(5)typeof + 类型检测

#define min(x, y) ({                               

         typeof(x) _min1 = (x);                          

         typeof(y) _min2 = (y);                          

         (void) (&_min1 == &_min2);             

         _min1 < _min2 ? _min1 : _min2; })



#define max(x, y) ({                              

         typeof(x) _max1 = (x);                         

         typeof(y) _max2 = (y);                         

         (void) (&_max1 == &_max2);           

         _max1 > _max2 ? _max1 : _max2; })

 (void) (&_x == &_y)
这句不是为了判断两个变量的地址是否相等,而是为了判断两个变量的类型是否相同;如果类型不同,编译阶段,编译器为告警!

         typeof(x) _min1 = (x);                          

         typeof(y) _min2 = (y);                          

可以防止类似min(a++,b++)歧义的存在
 

2、offsetof

  offsetof宏定义如下所示:

#define offsetof(type, member) ((size_t) &((type*)0)->member)

         根据优先级的顺序,最里面的小括号优先级最高,type *将整型常量0强制转换为type型的指针,且这个指针指向的地址为0,也就是将地址0开始的一块存储空间映射为type型的对象,接下来再对结构体中member成员进行取址,而整个type结构体的首地址是0,这里获得的地址就是member成员在type中的相对偏移量。再将这个偏移量强制转换成size_t型数据(无符号整型)。

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

 

3、container_of

#define container_of(ptr, type, member) ({          
            const typeof( ((type *)0)->member ) *__mptr = (ptr);    
            (type *)( (char *)__mptr - offsetof(type,member) );})

container_of宏的功能:通过一个结构体中某个成员的指针得到指向这个结构体的指针。ptr是结构成员指针,type是结构名,member是结构成员名。container_of宏由两部分实现:

(1)const typeof( ((type *)0)->member ) *__mptr = (ptr);                                                                                                                

       该语句定义了一个member类型的指针变量__mptr,并将ptr赋值给__mptr。此句的作用是检查参数ptr是否为结构体type成员member类型的指针!如果类型不符合,编译器将报错!

 

(2)(type *)( (char *)__mptr - offsetof(type,member) );

       该语句先将__mptr转化为char型指针(目的是char型指针加减运算是按1个字节移动的!),然后用__mptr(该成员的指针)减去该成员在结构中的地址偏移量,得到结构体的首地址,最后将运算结果转化为type类型指针,即得到指向结构体的指针。

 

offsetof宏和container_of宏 代码实验

#include <stdio.h>
#include <stdlib.h>
 
struct fox {
    unsigned long tail_length;
    unsigned long weight;
    unsigned char is_fantastic;
};
 
#define offsetof(type, member) ((size_t) &((type*)0)->member)
 
#define container_of(ptr, type, member) ({          
            const typeof( ((type *)0)->member ) *__mptr = (ptr);    
            (type *)( (char *)__mptr - offsetof(type,member) );})
 
int main()
{
    printf("tail_length offset: %un", offsetof(struct fox, tail_length));
    printf("weight offset: %un", offsetof(struct fox, weight));
    printf("is_fantastic offset: %un", offsetof(struct fox, is_fantastic));
 
    struct fox sfox  = { 10, 20, 1};
    struct fox *pfox = container_of(&sfox.is_fantastic, struct fox, is_fantastic);
    printf("tail_length: %un", pfox->tail_length);
    printf("weight: %un", pfox->weight);
    printf("is_fantastic: %un", pfox->is_fantastic);
 
    return 0;
}

实验结果:

tail_length offset: 0
weight offset: 8
is_fantastic offset: 16
tail_length: 10
weight: 20
is_fantastic: 1

 

4、list_for_each_entry

#define list_for_each_entry(pos, head, member)				
	for (pos = list_entry((head)->next, typeof(*pos), member);	
	     &pos->member != (head); 	
	     pos = list_entry(pos->member.next, typeof(*pos), member))

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

         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为链表头的实体链表,对实体链表中的数据结构进行处理;

 

参考:

https://blog.csdn.net/weixin_45228780/article/details/91869908?utm_medium=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase&depth_1-utm_source=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-4.nonecase

 

https://blog.csdn.net/huangjxbuaa/article/details/9200421?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

 

https://blog.csdn.net/whatday/article/details/100549368

最后

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

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

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

评论列表共有 0 条评论

立即
投稿
返回
顶部