Linux双链表

双链表基本结构定义

struct list_head{
struct list_head * next;
struct list_head * prev;
};

offsetof 宏

#define offsetof(TYPE,MEMBER) ((size_t) &((TYPE*)0->MEMBER))
  1. (TYPE*)0 将整数0强制转换成一个指向TYPE类型的指针,关键在于,这里并没有分配任何内存,只是告诉编译器有一个指向TYPE类型的指针,它的地址是0

  2. ((TYPE)0)->MEMBER是通过指针访问结构体的成员MEMBER,由于结构体的起始地址被认为是0,因此((TYPE)0)->MEMBER实际获取的是成员MEMBER相对于结构体起始地址的地址。

3.&((TYPE*)0)->MEMBER,这一步使用取地址运算符 &,获取上一步中得到的成员 MEMBER 的地址

4.(size_t) &((TYPE *)0)->MEMBER。这一步将上一步得到的地址(偏移量)强制转换为 size_t 类型。size_t 是一个无符号整数类型,通常用于表示对象的大小或偏移量。将其转换为 size_t 确保了偏移量以正确的类型表示,并且可以进行安全的算术运算。

container_of

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})
  1. typeof( ((type \*)0)->member ):获取成员类型

    • (type *)0:将整数 0 强制转换为指向 type 类型结构体的指针。这样做并不会访问实际的内存地址,只是为了进行类型推导。
    • ((type *)0)->member:通过空指针访问结构体成员 member。编译器会根据 type 的定义,推断出 member 的类型。
    • typeof( ((type *)0)->member ):使用 typeof 关键字获取 member 成员的类型。例如,如果 memberint 类型,则 typeof( ((type *)0)->member ) 的结果就是 int
  2. const typeof( ((type \*)0)->member ) \*__mptr = (ptr);:创建类型匹配的临时指针

    • const typeof( ((type *)0)->member ) *__mptr:声明一个类型为 const typeof( ((type *)0)->member ) * 的指针 __mptrconst 关键字表示该指针指向的内容是不可修改的。这样做是为了进行类型检查,防止传入的 ptr 指针类型与 member 成员类型不匹配。
    • = (ptr):将传入的 ptr 指针赋值给 __mptr

    这一步的目的是创建一个与 ptr 类型相同的临时指针,并进行类型检查。在一些老的 container_of 实现中,没有 consttypeof,直接使用 void * __mptr = (void *)(ptr);,这样做虽然简单,但缺少类型检查,不够安全。新的实现方式更严谨。

  3. (char \*)__mptr:将指针转换为字符指针

    • (char *)__mptr:将 __mptr 指针强制转换为 char * 类型。这是关键的一步,因为 char 类型的大小为 1 字节,将指针转换为 char * 类型后,进行指针的加减运算时,步长就是 1 字节,方便进行偏移量的计算。
  4. offsetof(type, member):计算成员偏移量

    • offsetof(type, member):这是一个宏,用于计算成员 member 在结构体 type 中的偏移量(以字节为单位)。
  5. (char *)__mptr – offsetof(type,member)`:计算结构体起始地址

    • (char *)__mptr - offsetof(type,member):从 __mptr 指针(指向成员的地址)中减去 member 成员的偏移量。由于 __mptr 已经被转换为 char * 类型,因此减法运算的单位是字节。计算结果就是结构体的起始地址。
  6. (type *)( (char *)__mptr – offsetof(type,member) )`:将结果转换为结构体指针

    • (type *)( ... ):将上一步计算得到的结构体起始地址强制转换为 type * 类型,得到指向结构体的指针。