Linux:
对于定义的一个结构体,有着对应的一套操作函数(eg:遍历、取头节点之类的),如果将对应的结构体指针直接放在结构体内,则操作函数的使用只能被动的限制于该结构体;
eg:struct page{
int a;
char bb;
struct page *prev, *next;
}
int getcount( struct page *head); 该函数将通过head头指针中的next变量来遍历所有结构体,该函数也就只限于page结构体;
---------------------------------------------------------
将指针提取出来的方式
eg:struct list_head{
struct list_head *prev, *next;
}
struct page{
int a;
char bb;
struct list_head plist;
}
int getcount( struct list_head *head);
则该函数可以通过head头指针来遍历所有结构体中的list_head成员变量(plist),而通过plist变量地址,可以取得对应的page结构体地址。因此,别的类型的结构体也可以通过内嵌list_head变量来组成链表,而getcout函数就可以用于所有这种类型的结构体操作
首先取出plist在page结构体中的位置偏移:
#define GETOFFSET(type, member) (unsigned long)(&((type*)0)->member)
再由plist的地址 - 该偏移值
windows下,在有关IOCP中有用到类似的地方:
// Calculate the address of the base of the structure given its type, and an
// address of a field within the structure.
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(UINT_PTR)(&((type *)0)->field)))
// Calculate the byte offset of a field in a structure of type type.
#define FIELD_OFFSET(type, field) ((LONG)(INT_PTR)&(((type *)0)->field))