概述
#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所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复