linux内核基础

1、offsetof(TYPE,MEMBER)

返回MEMBER在结构体TYPE中的偏移地址


#define  offsetof(TYPE, MEMBER)  ((size_t) &((TYPE *)0)->MEMBER)
 
(TYPE *)0将值0强制转换为TYPE结构体指针,&((TYPE *)0)->MEMBER找到MEMBER的地址,((size_t) &((TYPE *)0)->MEMBER)强制把MEMBER所在地址转换成long unsigned int。
巧妙之处在与使用了0地址,作为结构体指针,便宜地址 = 成员地址 - 结构体地址,而结构体地址是0,所以只要求出成员地址就可以了。


2、container_of(ptr, type, member)
ptr是member类型的指针,返回ptr指向的member所在的结构体的基地址


#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
 
首先申明一个type->member所属类型的指针变量mptr,值为ptr;
const typeof(((type *)0)->member) * __mptr = (ptr);
这时,mptr指向了ptr所指向的member变量。

(type *)((char *)__mptr - offsetof(type, member)); }) ,mptr - (member在结构体type中的偏移)= (member坐在结构体的地址),强转成type指针。


 
3、list_entry(ptr, type, member)
 


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


返回ptr指向的内存作为member变量所在的type类型结构体的地址


4、list_first_entry(ptr, type, member)、list_last_entry(ptr, type, member)
 
在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head:
 
此list_head并没有数据域,其作用主要是作为结构体中的成员变量被结构所继承,这样就可以通过list_head将各个成员连成一个循环双链表,使用list_entry找到各个结构体的地址了。注意list_head的头结点不使用。
 
list_fisrt_entry和list_last_entry第一个参数member类型指针相同,都是循环双向链表的头结点,只是在调用list_entry是一个是用来next指针,一个用prev指针。其作用都返回type类结构体的地址。


5、list_for_each_entry(pos, head, member)
表示从以head为头的双向循环列表中,一个一个拿出包含此list项目的结构体(pos的类型),并放到pos中
遍历以head作为循环双向链表头结点的pos类结构体,pos每次迭代指向list_head所在结构体,list_head在结构体中的名字是member。
 
head是循环双向链表的头结点;post是type类型指针,list_head在type结构体中的名字是member。
pos初始化为head->next坐在结构体;&pos->member != (head);表示此次迭代pos不是头结点所在结构体;pos=list_next_entry(pos,member))指向了下一个type结构体。

猜你喜欢

转载自blog.csdn.net/cityday/article/details/78062019