0 问题描述
/* Get typed element from list at a given position. */
#define list_entry(ptr, type, member) \
((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
这个宏的作用是根据一个"结构体成员的地址、结构体类型以及该结构体成员名"获得该结构体的首地址。
宏中的:
ptr ——结构体成员的地址
type ——结构体类型
member ——该结构体成员名
现在的问题是:如何根据一个结构体成员的地址、结构体类型以及该结构体成员名获得该结构体的首地址?这个宏是怎么做到的?
1 先看一下这个宏的一个应用场景:
对于一个结构体定义如下:
typedef struct xxx
{
……(结构体中其他域,令其总大小为size1)
type1 member;
……(结构体中其他域)
}type;
注意以下程序:
int main(){
type a;
type * b;
type1 * ptr;
ptr = &(a.member);
b = list_entry(ptr,type,member); //此时b指向a,得到了a的地址。
}
可见 ptr指向的是结构体a的member成员的地址。
通过 b = list_entry(ptr,type,member); 可使b指向a,得到了a的地址。
2 解析
#define list_entry(ptr, type, member)
((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
先看&((type *)0)->member
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是type *
型的,所以可取到以“0”为基地址的一个type型结构体member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。
由此可见 ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
(char *)(ptr)
使得指针的加减操作步长为一字节,(unsigned long)(&((type *)0)->member)
等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者一减便得出该结构体的地址。