linux源代码里的链表结构可能与教课书里的不太一样,如下:
struct list_head {
struct list_head *next, *prev;
};
可以看到,里面没有数据域,那么这个结构在linux源码里怎么应用呢,看一个例子:
struct vblk { /* Generalised VBLK */
u8 name[64];
u64 obj_id;
u32 sequence;
u8 flags;
u8 type;
union {
struct vblk_comp comp;
struct vblk_dgrp dgrp;
struct vblk_disk disk;
struct vblk_part part;
struct vblk_volu volu;
} vblk;
struct list_head list;
};
很明显,跟我们平常用的相反,它将list_head结构挂在了数据里面,为了能访问到数据域的地址,linux源码里提供了一个叫list_entry的:
#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_entry的三个入参分别是,指针的地址,数据域的结构类型和指针成员,实例如:定义一个,
struct vblk sample;
和
struct list_head *ptr;
我们就这样用list_entry:
list_entry(ptr, struct vblk, list);
list_entry返回的就是包含ptr地址的vblk结构的首地址,这样我们就可以任意访问这个结构里的数据字段了。