美文网首页
container_of

container_of

作者: _invincible_ | 来源:发表于2021-01-10 20:06 被阅读0次

    功能

    通过结构体成员变量的地址获取其结构体变量(container)的地址。

    • 第一个参数 ptr 是成员的地址
    • 第二个参数 type 是container的类型
    • 第三个参数 member 是成员在container中的名称
    • 返回的是container的地址

    定义

    // linux-3.10/include/linux/kernel.h
    
    /**
     * container_of - cast a member of a structure out to the containing structure
     * @ptr:        the pointer to the member.
     * @type:       the type of the container struct this is embedded in.
     * @member:     the name of the member within the struct.
     *
     */
    #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)
    

    例子

    #include <stdlib.h>
    #include <stdio.h>
    
    /**
     * container_of - cast a member of a structure out to the containing structure
     * @ptr:        the pointer to the member.
     * @type:       the type of the container struct this is embedded in.
     * @member:     the name of the member within the struct.
     *
     */
    #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)
    
    
    struct node_t {
      struct node_t *next;
    };
    
    struct my_struct {
       int a;
       char b;
       struct node_t c;
    };
    
    
    int main(){
        struct my_struct m;
        struct my_struct m2;
        struct my_struct *pm2;
        
        int * pa = &m.a;
        char * pb = &m.b;
        struct node_t * pc = &m.c;
        
        void *ptr;
        
        ptr = container_of(pc, struct my_struct, c);
        
        printf("&m: %p, ptr: %p\n", &m, ptr);
        ptr = NULL;
        
        ptr = container_of(pa, struct my_struct, a);
        printf("&m: %p, ptr: %p\n", &m, ptr);
        ptr = NULL;
            
        ptr = container_of(pb, struct my_struct, b);
        printf("&m: %p, ptr: %p\n", &m, ptr);
        
        m.c.next = &m2.c;
        pm2 = container_of(m.c.next, struct my_struct, c);
        printf("&m2: %p, pm2: %p\n", &m2, pm2);
    
        return 0;
    }
    
    
    
    &m: 0x7ffe4c4393d0, ptr: 0x7ffe4c4393d0
    &m: 0x7ffe4c4393d0, ptr: 0x7ffe4c4393d0
    &m: 0x7ffe4c4393d0, ptr: 0x7ffe4c4393d0
    &m2: 0x7ffe4c4393c0, pm2: 0x7ffe4c4393c0
    
    

    简单解释

    1.计算结构体成员相对 container 的偏移
    2.用当前成员的地址减去偏移得到container结构体的地址

    第一步的实现

    (size_t) &((TYPE *)0)->MEMBER
    
    #include <stdlib.h>
    #include <stdio.h>
    
    struct node_t {
      struct node_t *next;
    };
    
    struct my_struct {
       int a;
       char b;
       struct node_t c;
    };
    
    
    int main(){
        struct my_struct m;
        printf("&m: %p\n", &m);
        printf("&m.a: %p\n", &m.a);
        printf("&m.b: %p\n", &m.b);
        printf("&m.c: %p\n", &m.c);
        printf("%lu\n", (size_t) & ((struct my_struct *)0)->a);
        printf("%lu\n", (size_t) & ((struct my_struct *)0)->b);
        printf("%lu\n", (size_t) & ((struct my_struct *)0)->c);
        return 0;
    }
    
    
    &m: 0x7ffd2af67fd0
    &m.a: 0x7ffd2af67fd0
    &m.b: 0x7ffd2af67fd4
    &m.c: 0x7ffd2af67fd8
    0
    4
    8
    

    第二步的实现

    const typeof( ((type *)0)->member ) *__mptr = (ptr);    
    (type *)( (char *)__mptr - offsetof(type,member) )
    
    #include <stdlib.h>
    #include <stdio.h>
    
    struct node_t {
      struct node_t *next;
    };
    
    struct my_struct {
       int a;
       char b;
       struct node_t c;
    };
    
    
    int main(){
        struct my_struct m;
        struct my_struct *pm;
    
        size_t offsetof_c = (size_t) & ((struct my_struct *)0)->c;
        printf("offsetof_c: %lu\n", offsetof_c);
    
        typeof(((struct my_struct *)0)-> c) *__mptr = &m.c;
        printf("__mptr: %p\n", __mptr);
        
        pm = (struct my_struct *)( (char *)__mptr - offsetof_c);
        printf("&m: %p, pm: %p\n", &m, pm);
    
        return 0;
    }
    
    
    offsetof_c: 8
    __mptr: 0x7ffcc562a9c8
    &m: 0x7ffcc562a9c0, pm: 0x7ffcc562a9c0
    
    

    常见应用

    // include/linux/rbtree.h
    #define rb_entry(ptr, type, member) container_of(ptr, type, member)
    
    // include/linux/vmalloc.h
    struct vmap_area {
            unsigned long va_start;
            unsigned long va_end;
            unsigned long flags;
            struct rb_node rb_node;         /* address sorted rbtree */
            // ...
    };
    
    // mm/vmalloc.c
    static struct vmap_area *__find_vmap_area(unsigned long addr)
    {
            struct rb_node *n = vmap_area_root.rb_node;
    
            while (n) {
                    struct vmap_area *va;
    ...
                    va = rb_entry(n, struct vmap_area, rb_node);
    ...
            }
    ...
    }
    
    
    // include/linux/list.h
    #define list_entry(ptr, type, member) \
            container_of(ptr, type, member)
    
    // include/linux/types.h
    struct list_head {
            struct list_head *next, *prev;
    };
    
    
    // include/linux/vmalloc.h
    struct vmap_area {
    ...
            struct list_head list;          /* address sorted list */
    ...
    };
    
    // mm/vmalloc.c
    static void *s_next(struct seq_file *m, void *p, loff_t *pos)
    {
            struct vmap_area *va = p, *next;
    
            ++*pos;
            next = list_entry(va->list.next, typeof(*va), list);
    ...
            return NULL;
    }
    
    
    

    相关文章

      网友评论

          本文标题:container_of

          本文链接:https://www.haomeiwen.com/subject/zvgxaktx.html