首先说明这两个是同一个含义!
container_of
内核定义
#define container_of(ptr, type, member) \
(type *)((char *)(ptr) - (char *) &((type *)0)->member)
作用:
用于根据结构体成员的指针计算出对应的结构体的指针
解释:
这个宏包含了三个参数:
ptr:结构体成员的指针。
type:结构体类型。
member:结构体成员变量的名称。
宏的作用是根据给定的结构体成员的指针 ptr,返回对应的结构体的指针。它使用了指针运算和类型转换来实现。
宏的具体实现如下:
首先,(type *)0
将一个空指针强制类型转换为指向 type 类型的指针,并且取得该指针指向的内存地址。
接着,&((type *)0)->member
取得了结构体成员 member 的偏移量,也就是 member 相对于结构体起始地址的偏移量。
(char *)&((type *)0)->member
将偏移量转换为字符指针,这样我们就可以通过指针运算来进行偏移操作。
(char *)(ptr) - (char *)&((type *)0)->member
计算结构体成员相对于结构体起始地址的偏移量,并将结果赋给一个指针类型,这样就得到了结构体的起始地址。
最后,(type *)
将结果强制类型转换为指向 type 类型的指针,即返回了结构体的指针。
详解
(char *)(ptr) - (char *)&((type *)0)->member
这部分代码使用指针运算来计算结构体成员相对于结构体起始地址的偏移量。这里的实现依赖于以下几个原理:
1、空指针操作:(type *)0
将空指针强制类型转换为 type 类型的指针,其中 type 是一个结构体类型。通过将空指针转换为结构体类型的指针,我们可以获取该结构体的起始地址。
2、地址运算:&((type *)0)->member
获取了结构体成员 member 相对于结构体起始地址的偏移量。这是因为结构体中的各个成员在内存中是按照声明顺序依次存储的,而结构体的起始地址就是第一个成员的地址。因此,通过取 &((type *)0)->member 的地址,我们可以获取到该成员相对于结构体起始地址的偏移量。
3、指针运算:(char *)(ptr) - (char *)&((type *)0)->member
使用字符指针进行指针运算,将结构体成员的指针 ptr 减去结构体成员相对于结构体起始地址的偏移量,即可得到结构体的起始地址。这是因为字符指针的单位为字节,所以减法运算得到的结果是以字节为单位的偏移量。
举例
设有如下结构体定义:
typedef struct xxx
{
……(结构体中其他域,令其总大小为size1)
type_1 member;
……(结构体中其他域)
}type;
定义变量:
type a;
type * b;
type_1 * ptr;
执行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
则可使b指向a,得到了a的地址。