我是靠谱客的博主 微笑蓝天,这篇文章主要介绍list_for_each_entry(pos, head, member)的内幕,现在分享给大家,希望可以做个参考。

list_for_each_entry(pos, head, member)是一个遍历链表的操作,但是从中涉及到的小函数很多,想要彻底高清除,需要下一点功夫。

下面一步一步的分解该宏定义。抽丝剥茧的看看这个宏定义到底最后定义成什么了。

复制代码
1
2
3
4
#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))

宏定义如上,里面关键的宏定义 list_entry是什么呢?恩,是它

复制代码
1
2
#define list_entry(ptr, type, member) container_of(ptr, type, member)

那么, list_for_each_entry最终简化成

复制代码
1
2
3
4
#define list_for_each_entry(pos, head, member) for (pos = container_of((head)->next, typeof(*pos), member); &pos->member != (head); pos = container_of(pos->member.next, typeof(*pos), member))

好了,可以看出,整个宏定义的关键就在于 container_of上面。而这个宏定义如下:

复制代码
1
2
3
#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})

这个定义看起来特别复杂,但是一步一步展开后,它原理特别简单。分析以下分为两步( 注意:其中member是type类型中的一个变量,还有ptr是指向member类型的指针

1:定义一个*__mptr等于ptr。其中typeof的作用就是不用定义类型直接可以推断出此类型,详细信息可以到网上搜一下。

2:根据offsetof(type,member) 是求偏移量的。然后用*__mptr减去偏移量。那不就是结构体type类型所对应的地址么?

用如下例子可以看出

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h> #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) );}) struct test_struct { int num; char ch; float f1; }; int main(void) { struct test_struct *pos; struct test_struct init_struct ={12,'a',12.3}; int *ptr_ch1 = &init_struct.num; pos = container_of(ptr_ch1,struct test_struct,num); printf("%p----%pn",pos,&init_struct); char *ptr_ch2 = &init_struct.ch; pos= container_of(ptr_ch2,struct test_struct,ch); printf("%p----%pn",pos,&init_struct); float *ptr_ch3 = &init_struct.f1; pos = container_of(ptr_ch3,struct test_struct,f1); printf("%p----%pn",pos,&init_struct); printf("test_struct->num =%dn",pos->num); printf("test_struct->ch =%cn",pos->ch); printf("test_struct->ch =%fn",pos->f1); return 0; }
得到的结果:

复制代码
1
2
3
4
5
6
0xbf942ca4----0xbf942ca4 0xbf942ca4----0xbf942ca4 0xbf942ca4----0xbf942ca4 test_struct->num =12 test_struct->ch =a test_struct->ch =12.300000
可知我们的思路是正确的。

一般条件下,调用函数中的member为list_head类型,那list_for_each_entry的函数就可以用以下内容概括了:


即根据list_head的遍历找出下一个list_head。然后推断出整个pos的类型第地址。以便求出里面的数据


最后

以上就是微笑蓝天最近收集整理的关于list_for_each_entry(pos, head, member)的内幕的全部内容,更多相关list_for_each_entry(pos,内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部