container_of 详解

container_of 详解

container_of宏是用在已知一个struct中的元素地址,计算出此元素所在结构体的首地址。


一、定义

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

其中 ptr 指的是元素的指针,type是结构体的类型,member是元素类型。
举个例子:

#include
#include

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

struct Test{
        int m_a;
        int m_b;
        int m_c;
};

int main()
{
        struct Test test;
        test.m_b = 1;
        int* ptr = &(test.m_b);

        printf("container_of_addr = %x\n test_addr = %x\n", \
                container_of(ptr, struct Test, m_b), &test);

        return 0;
}

运行结果:

container_of_addr = 1429a730
test_addr = 1429a730

从这里可以看出,通过一个struct的成员的地址 ptr ,结构体的类型 struct Test,成员名 m_b。就可以得到ptr所对应的结构体变量的首地址。

二、原理

原理其实很简单,一句话就可以概括,就是通过元素的地址减去结构体成员在结构体中的地址偏移。如下图:
container_of 详解_第1张图片
其中:offsetof(type, member)函数就是用来求offset(结构体成员在结构体中的地址偏移)。来看一看offsetof的定义:

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

这里的 (type *)0 表示,骗编译器我有一个起始地址为0的类型为type的变量,&((TYPE *)0)->MEMBER 所以member的地址就是member在struct中的地址偏移。
通过 head = ptr - offset 就可以得到struct的首地址,再将head强制转换为相应的struct类型的指针即可。

你可能感兴趣的:(Linux,linux,c)