说明

        本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

内容来源

目录:

1.功能简介:

  若仅知某 结构体的数据类型 和其中一个 成员变量的数据类型变量名,但想对该结构体变量中其他成员变量进行操作,则需先得到该 结构体变量首地址。则可采用container_of宏进行获得。

2.源码及注释:

/**
 * @brief 通过“结构体成员”的地址与“结构体”的类型推导出“结构体”的首地址
 *
 * @ptr:    “结构体成员”的地址
 * @type:   “结构体”的类型
 * @member: “结构体成员”的名字
 */
#ifndef container_of
#define container_of(ptr, type, member)                       \
    ({                                                        \
        const typeof(((type *)NULL)->member) *__mptr = (ptr); \
        (type *)((char *)__mptr - offsetof(type, member));    \
    })
#endif
/*
    (1).typeof()返回传入数据的类型,如int a = 3;typeof(a) = int
    (2.offsetof(type, member):在类型为type的结构体中member成员,在该结构体中的偏移量
        type:结构体类型,member:结构体中某个成员
分析:
    A = ((type *) NULL)表示:type类型的指针地址为0,
    B = (A->member)表示:该结构体类型(地址为0)的成员member
    C = typeof(B)表示:返回结构体成员member的数据类型
    D = const C* __mptr = (ptr)表示:__mptr的地址为ptr的成员地址(数据类型统一的成员地址)
    E = offsetof(type, member)表示:类型为type的结构体中member成员,member在该结构体中的偏移量
    F = (type *) ((char *)__mptr - E
      = ptr - E (忽略类型) = 成员的地址 - 成员的偏移量 = 结构体的的初始地址 = 结构体指针地址
*/

3.源文件测试理解步骤

#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>

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

struct test_struct
{
    int data;
    bool pending;
    char name;
    void *pointer;
};

int main(int argc, char *argv[])
{
    /*
        1.理解typedef关键字的作用
        typeof(((struct test_struct *)NULL)->name) = char
        typeof()返回传入数据的类型,如int a = 3;typeof(a) = int
    */
    const typeof(((struct test_struct *)NULL)->name) a = 'a';
    printf("%c\n", a);

    /*
        2.获取结构体成员的地址
        const typeof(((type *)NULL)->member) *__mptr = (ptr);
        根据结构体成员名得到结构体成员名的数据类型,再将已知的成员地址传入
     */
    struct test_struct data;
    const typeof(((struct test_struct *)NULL)->name)* _a = &data.name;
    printf("member address:%p\n", _a);

    /*
        3.获取结构体成员的地址与结构体的偏移量
        offsetof(type, member)
        在类型为type的结构体中member成员,在该结构体中的偏移量
     */
    printf("member offset:%ld\n", offsetof(struct test_struct, name));

    /*
        4.最终结果,获得结构体地址
     */
    printf("struct address:%p\n", \
        (struct test_struct *)((char *)_a - offsetof(struct test_struct, name)));
    printf("struct address:%p\n", &data);

    return 0;
}