C语言链表常用宏——offsetof和container_of

链表是内核最经典的数据结构之一,说到链表就不得不提及内核最经典(没有之一)的宏container_of

先看看代码:

#include 
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)

#define container_of(ptr, type, member) ({          \
        const typeof( ((type *)0)->member ) *__mptr = (const typeof( ((type *)0)->member ) *)(ptr); \
        (type *)( (char *)__mptr - offsetof(type,member) );})

几个关键内容分析一下:

typeof

typeof是GNU对C新增的一个扩展关键字,用于获取一个对象的类型,在很多时候我们处理的对象通常是一个指针,而此时如果想知道指针所指向的对象的类型,typeof就派上用场了,详见GNU的官方文档:http://gcc.gnu.org/onlinedocs/gcc/Typeof.html

offsetof

offsetof是返回结构体TYPEMEMBER成员相对于结构体首地址的偏移量,以字节为单位。

(TYPE *)0,将 0 强制转换为TYPE型指针,记 p = (TYPE *)0p是指向TYPE的指针,它的值是0。那么 p->MEMBER 就是 MEMBER 这个元素了,而&(p->MEMBER)就是MEMBER的地址,编译器认为0是一个有效的地址,则基地址为0,这样就巧妙的转化为了TYPE中的偏移量。再把结果强制转换为size_t型的就OK了。

container_of

container_of的主要作用是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。

创建一个类型为const typeof( ((type *)0)->member ) *,即类型为type结构的member域所对应的对象类型的常指针__mptr,并用ptr初始化之,这样一来,__mptr就指向了某一个typemember域。因为数据结构是顺序存储的,此时如果知道membertype结构中的相对偏移,那么用__mptr减去此偏移便是ptr所属的type的地址。

container_of最典型的应用就是根据链表节点获取链表上的元素对象。

我是咕咕鸡,一个还在不停学习的全栈工程师。
热爱生活,喜欢跑步,家庭是我不断向前进步的动力。

你可能感兴趣的:(C语言链表常用宏——offsetof和container_of)