list_head
/**
* Double List structure
*/
struct rt_list_node
{
struct rt_list_node *next; /**< 指向下一个节点. */
struct rt_list_node *prev; /**< 指向上一个节点。. */
};
typedef struct rt_list_node rt_list_t; /**< Type for lists. */
RT-Thread 内核定义了 rt_list_node数据结构,字段 next 和 prev 分别表示通用双向链表向前和向后的指针元素。不过,值得特别关注的是,rt_list_node 字段的指针中存放的是另一个 rt_list_node字段的地址,而不是含有 list_head 结构的整个数据结构地址
用 rt_list_node数据结构构造的一个双向链表如下所示:
rt_list_for_each
宏定义展开(原型)
/**
* rt_list_for_each -遍历链表,实际是得到指定链表节点对应的数据对象结构
* @pos: 指向宿主结构的指针,在for循环中是一个迭代变量
* @head: 链表头
*/
#define rt_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
通过宏展开可以看出,实际上是一个 for 循环,利用传入的pos 作为循环变量,从表头 head开始,逐项向后(next方向)移动 pos ,直至又回到 head,注意:此宏必要把list_head放在数据结构第一项成员,至此,它的地址也就是结构变量的地址。
rt_container_of
/**
* rt_container_of - 获取type结构体中member成员在这个结构体中的偏移地址
* struct type.
*/
#define rt_container_of(ptr, type, member) \
((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
将宏展开分析
1。0 将0视作地址
2.((type *)0 强制转换为自定义结构体类型
3.((type *)0)->list
4. &((type *)0)->list 取得list成员的地址
其中(char*)(ptr) 为将ptr转为char*类型,这样就将地址加减操作步长减为一个字节,
unsign long将得到的偏移量转为32/64位数字,将List指针和偏移量相减便得到结构地址,再用(type *)转为相应类型地址。
宏作用总结:
计算size大小,结构体的起始地址 = (type *)((char *)ptr - size) (注:强转为该结构体指针)
现在我们知道container_of()的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。
container_of(ptr,type,member),这里面有ptr,type,member分别代表指针、类型、成员。