linux内核中的list_for_each_entry函数
程序员文章站
2022-03-09 21:44:44
...
通过结构体成员获取结构体地址
代码仅作解释,不能直接运行
// 结构体 :该结构体里面有一个节点 node,该节点会插入到 一个链表里面
struct input_handler {
int minor;
struct list_head node;
};
// 链表
struct list_head {
struct list_head *next, *prev;
};
int main(void)
{
// 实化一个链表、创建一个结构体指针 -- 忽略链表初始化和节点插入过程,假设这些都已经完成
struct input_handler *handler;
struct list_head input_handler_list;
/* input_handler_list链表里面链接的节点 是 handler结构体里的一个成员 -- node
参数①:结构体指针
参数②:链表头节点地址
参数③:节点名字 */
list_for_each_entry(handler, &input_handler_list, node)
}
static inline void prefetch(const void *x) {;}
// ----------- 分析1 list_for_each_entry(pos, head, member) -------------------------------//
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/*
参数1:pos = handler 结构体指针 【解释:pointer of struct】
参数2: head = &input_handler_list 【链表头节点的地址,head就变成了一个指针 】
参数3:member = node 【节点的名字】
【1】for结构的初始化:得到了链表中 第一个节点的 父结构体指针,得到结构体指针就能操作该结构体
pos = list_entry( (head)->next, typeof(*pos), member );
【1.1】分析list_entry
*/
// ----------- 分析2 list_entry(ptr, type, member) -------------------------------//
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/*
参数1:ptr = (head)->next 【链表头节点的下一个节点】
参数2: type = typeof(*pos) = typeof(*handler) 【得到结构体类型】
参数3:member = node 【节点的名字】
【1.1】list_entry的目的似乎是为了将参数的表达变的简单后,再进行具体操作
container_of(ptr, type, member)
【1.1.1】分析container_of
*/
// ----------- 分析3 container_of(ptr, type, member) -------------------------------//
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
/*
参数1:ptr = (head)->next 【链表头节点的下一个节点】
参数2: type = typeof(*pos) = typeof(*handler) 【得到结构体类型】
参数3:member = node 【节点的名字】
【1.1.1】
第一行分析
简化成:const XXX *__mptr = (ptr); 等价于 const struct list_head *__mptr = input_handler_list->next;
第一行定义了一个指针并初始化,初始化结果就是该指针就变成 head->next指针,存储的是节点的地址
指针类型见下分析:
【(type *)0】将0强转为一个地址,地址(0x0000)变成一个type类型结构体的首地址,这里的type就是input_handler
【typeof( ((type *)0)->member )】 取得这个type类型结构体中名为member的成员 的类型, 这里的member就是node
第2行分析:
简化成:(type *)( 地址 ); 等价于 struct input_handler *( 地址 )
【 (char *)__mptr 】将__mptr从结构体指针转化为无符号整形指针,(char *)__mptr = 节点的地址
offsetof得到的是一个无符号整形值
最后结果就是 pos = list_entry( (head)->next, typeof(*pos), member );
= container_of(ptr, type, member);
= ({ const struct list_head *__mptr = input_handler_list->next;
(struct input_handler *)( 地址 )
*/
// ----------- 分析4 offsetof(TYPE, MEMBER) -------------------------------//
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/*
参数2: type = typeof(*pos) = typeof(*handler) 【得到结构体类型】
参数3:member = node 【节点的名字】
【(TYPE *)0)->MEMBER】 取结构体中的成员
【&(TYPE *)0)->MEMBER】取成员地址,由于该结构体地址从0x0开始,所以成员地址就是偏移地址
【(size_t)addr】将获得的地址强制转化为 无符号整型 size_t
*/
宏定义使用
代码可直接运行
/* */
#include <stdio.h> // ptintf; scanf
#include <stdlib.h> // 分配内存,释放内存
// 不要少了() -- ({})
#define XXX ({ \
int i=5; \
(int)(i-1); })
int main(int argc, char **argv)
{
int p;
int t;
p = XXX;
// 不要少了() -- ({})
t = ({
int j=10;
(int)(j-1);
});
printf("%d\n\r",p);
printf("%d\n\r",t);
return 0;
}
jj
上一篇: 工厂模式(依赖反射)