Bootstrap

container_of宏简介

宏函数作用
container_of宏的作用是通过结构体内某个成员变量的地址和该变量名,以及结构体类型。找到该主结构体的地址。这里使用的是一个利用编译器技术的小技巧,即先求得结构成员在结构中的偏移量,然后根据成员变量的地址反过来得出主结构体的地址

原型

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


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

参数解释:

宏分解
typeof
首先看下typeof,是用于返回一个变量的类型,这是GCC编译器的一个扩展功能,也就是说typeof是编译器相关的。既不是C语言规范的所要求,也不是某个标准的一部分。例

#include<stdio.h>
#include<string.h>

typedef struct student
{
    int age;
    char name[128];
}Student_t;

int main()
{
    Student_t  stu;
    stu.age=18;
    strncpy(stu.name,"qingmu",6);

    typeof(stu.age)  xx=100;
    typeof(stu.name) yy="aaa";
    printf("xx is : %d \nyy is : %s \n", xx,yy);

    return 0;
}

执行结果:

xx is : 100 
yy is : aaa 

const typeof(((type )0)->member)__mptr = (ptr)
这句代码意思是用typeof()获取结构体里member成员属性的类型,然后定义一个该类型的临时指针变量__mptr,并将ptr所指向的member的地址赋给__mptr;

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

size_t是标准C库中定义的,在32位架构中被普遍定义为:typedef unsigned int size_t;
而在64位架构中被定义为:typedef unsigned long size_t;
为了使程序有很好的移植性,因此内核使用size_t和,而不是int,unsigned。
((size_t) &((TYPE*)0)->MEMBER) 结合之前的解释,我们可以知道这句话的意思就是求出MEMBER相对于0地址的一个偏移值。

#include<stdio.h>
#include<string.h>

typedef struct student
{
    int age;
    char name[128];
    int id;
}Student_t;

int main()
{
    Student_t  stu;
    stu.age=18;
    strncpy(stu.name,"qingmu",6);
    stu.id=100;


    printf("age addr :  %p\n",&stu.age);   
    printf("name addr :%p\n",&stu.name);
    printf("name addr :%p\n",&stu.id);
    printf("age 具结构体首地址的偏移 = %d\n",((int)&((struct student *)0)->age));
    printf("name 具结构体首地址的偏移 = %d\n",((int)&((struct student *)0)->name));
    printf("id 具结构体首地址的偏移 = %d\n",((int)&((struct student *)0)->id));
    return 0;
}

运行结果:

age addr : 0x7fff44a10e80
name addr :0x7fff44a10e84
name addr :0x7fff44a10f04
age 具结构体首地址的偏移 = 0
name 具结构体首地址的偏移 = 4
id 具结构体首地址的偏移 = 132


(type *)((char *)__mptr - offsetof(type, member))
这句话的意思就是,把 __mptr 转换成 char * 类型, 因为 offsetof 得到的偏移量是以字节为单位。 两者相减得到结构体的起始位置, 再强制转换成 type 类型。例

#include<stdio.h>
#include<stdlib.h>
#include <string.h>

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
        const typeof( ((type *)0)->member ) *__mptr = (ptr); \
        (type *)( (char *)__mptr - offsetof(type,member) );})
        
typedef struct student
{
    int age;
    char name[128];
    int  id; 
}Student_t;

int main()
{
        Student_t *sptr = NULL;
        Student_t stu;
    stu.age=18;
        strncpy(stu.name,"qingmu",6);
        stu.id=100;

        sptr = container_of(&stu.age,Student_t,age);
        printf("sptr=%p\n",sptr);
        sptr = container_of(&stu.name,Student_t,name);
        printf("sptr=%p\n",sptr);
        sptr = container_of(&stu.id,Student_t,id);
        printf("sptr=%p\n",sptr);


        printf("age:%p  name:%p  id:%p  size:%ld\n", \
        &stu.age,&stu.name,&stu.id,sizeof(stu));
        return 0;    
}

运行结果如下:

ptr=0x7ffca8831e50
sptr=0x7ffca8831e50
sptr=0x7ffca8831e50
age:0x7ffca8831e50  name:0x7ffca8831e54  id:0x7ffca8831ed4  size:136

可以看出container_of宏,可以完美的通过结构体变量指针和结构体类型的到结构体的首地址。

原文链接:

container_of宏简介_container_of]-CSDN博客

;