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: %u\n", offsetof(struct fox, tail_length));
    printf("weight offset: %u\n", offsetof(struct fox, weight));
    printf("is_fantastic offset: %u\n", 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: %u\n", pfox->tail_length);
    printf("weight: %u\n", pfox->weight);
    printf("is_fantastic: %u\n", 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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值